Welcome to my React Learning Journey! Here, I document useful tips, shortcuts, and best practices I discover along the way. This section will grow as I learn more. Enjoy the colorful notes and handy examples! π
π Official React Docs (Beta): https://react.dev/learn
- JSX lets you write HTML-like code in JavaScript files.
- Babel compiles JSX to
React.createElement
calls. - JSX in React Docs
Example:
const element = <h1>Hello, world!</h1>;
- Use
ReactDOM.render
(in older apps) or just return components in your app tree. - Rendering in React Docs
Example:
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
- Default export:
export default App; // import App from './App';
- Named export:
export function Header() {} // import { Header } from './Header';
- You can have one default export and many named exports per file.
- Modules in React Docs
- Organize by feature or component.
- Common structure:
src/ components/ Header.js Footer.js App.js index.js styles/ App.css
- Use PascalCase for component files:
MyComponent.js
- Use
{/* ... */}
for JSX comments. - Use
//
or/* ... */
for JS comments.
Example:
// This is a JS comment
{/* This is a JSX comment */}
- Always add a unique
key
prop when rendering lists. - Lists & Keys in React Docs
Example:
{items.map(item => <li key={item.id}>{item.name}</li>)}
- Use
<></>
or<React.Fragment></React.Fragment>
to group elements without adding extra nodes to the DOM. - Fragments in React Docs
Example:
return (
<>
<h1>Title</h1>
<p>Description</p>
</>
);
Modern code editors like VS Code support handy shortcuts (snippets) for quickly scaffolding React components. Here are two of the most popular ones:
What it does:
- Generates a boilerplate for a React function component using an arrow function.
Example:
import React from 'react';
const MyComponent = () => {
return (
<div>
MyComponent
</div>
);
};
export default MyComponent;
How to use:
- Type
rfa
in a new.js
or.jsx
file and hitTab
(if you have the ES7+ React/Redux/React-Native snippets extension installed in VS Code).
What it does:
- Generates a React function component using an arrow function and immediately exports it as default.
Example:
import React from 'react';
const MyComponent = () => {
return (
<div>
MyComponent
</div>
);
};
export default MyComponent;
How to use:
- Type
rafc
and hitTab
(with the same extension as above).
- State is a built-in object that stores property values that belong to a component.
- When state changes, the component re-renders to reflect those changes.
- State in React Docs
Use Case:
- Tracking user input, toggling UI elements, counters, form data, etc.
- Hooks are special functions that let you "hook into" React features (like state and lifecycle methods) in function components.
- Introduced in React 16.8, hooks allow you to use state and other React features without writing a class.
- Hooks in React Docs
Common Hooks:
useState
β for state managementuseEffect
β for side effects (like fetching data)useContext
β for context API
What it does:
- Lets you add state to function components.
- useState in React Docs
Syntax:
const [state, setState] = useState(initialValue);
Example: Counter
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Add</button>
<button onClick={() => setCount(count - 1)}>Subtract</button>
</div>
);
}
How it works:
count
is the current state value.setCount
is the function to update the state.useState(0)
sets the initial value to 0.
- The building block of any React app. Think of components as reusable, self-contained pieces of UI.
- Components in React Docs
Example:
function Welcome(props) {
return <h1>Hello, {props.name}!</h1>;
}
// Usage:
<Welcome name="Alice" />
- Props (short for "properties") are how you pass data from a parent component to a child component.
- Props are read-only in the child component.
- Props in React Docs
Example:
function Greeting(props) {
return <p>Welcome, {props.user}!</p>;
}
<Greeting user="Bob" />
children
is a special prop that allows you to pass elements/components between the opening and closing tags of a component.- Children in React Docs
Example:
function Card(props) {
return <div className="card">{props.children}</div>;
}
<Card>
<h2>Title</h2>
<p>This is inside the card!</p>
</Card>
- Prop Drilling is the process of passing data from a parent component down to deeply nested child components via props, even if intermediate components don't need the data themselves.
- Prop Drilling in React Docs
Example:
function Grandparent() {
const message = "Hello from Grandparent!";
return <Parent message={message} />;
}
function Parent(props) {
return <Child message={props.message} />;
}
function Child(props) {
return <p>{props.message}</p>;
}
Styling is a big part of building beautiful React apps. Here are all the main ways to style your components, with examples and tips!
- What: Traditional CSS files (e.g.,
App.css
) imported at the top level. - Use Case: App-wide styles, resets, typography, colors.
Example:
/* App.css */
body {
background: #f0f0f0;
font-family: 'Segoe UI', sans-serif;
}
import './App.css';
- What: Import a CSS file just for one component (e.g.,
Button.css
). - Use Case: Styles that only apply to a specific component.
Example:
/* Button.css */
.button {
background: #007bff;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
}
import './Button.css';
function Button() {
return <button className="button">Click me</button>;
}
- What: Pass a
style
prop with a JS object. - Use Case: Quick, dynamic, or one-off styles.
Example:
function Box() {
return <div style={{ background: 'yellow', padding: 20 }}>Inline styled!</div>;
}
- What: Change styles based on state or props.
- Use Case: Highlight active items, show/hide, change color, etc.
Example:
function Toggle({ isActive }) {
return (
<button
style={{
background: isActive ? 'green' : 'gray',
color: 'white',
}}
>
{isActive ? 'Active' : 'Inactive'}
</button>
);
}
- What: Locally scoped CSS files (e.g.,
Button.module.css
). - Use Case: Avoids class name collisions, great for large apps.
Example:
/* Button.module.css */
.special {
color: orange;
font-weight: bold;
}
import styles from './Button.module.css';
function Button() {
return <button className={styles.special}>Module Button</button>;
}
- What: Use libraries (like
styled-components
,emotion
) to write CSS in JS files. - Use Case: Dynamic, themeable, and scoped styles with JS power.
Example (styled-components):
import styled from 'styled-components';
const FancyButton = styled.button`
background: hotpink;
color: white;
padding: 10px 20px;
border: none;
border-radius: 8px;
`;
function App() {
return <FancyButton>Styled!</FancyButton>;
}
- Use CSS Modules or CSS-in-JS for large projects to avoid conflicts.
- Use global CSS for resets and base styles only.
- Use inline/dynamic styles for quick, state-based changes.
- Keep style logic close to the component it affects.
- Use BEM or similar naming for global classes.
- Global CSS: App-wide, imported once.
- Component CSS: Imported per component.
- Inline/Dynamic: For quick or state-based styles.
- CSS Modules: Scoped, avoids conflicts.
- Styled Components: Powerful, dynamic, and themeable.
Mix and match these techniques for beautiful, maintainable React apps! π¨β¨
- JSON (JavaScript Object Notation) is a lightweight data format for storing and transporting data.
- It's easy for humans to read and write, and easy for machines to parse and generate.
Example:
{
"name": "John Doe",
"age": 30,
"city": "New York",
"hobbies": ["reading", "swimming"]
}
- JSON Server is a full fake REST API that you can use for prototyping and mocking.
- It creates a REST API from a JSON file with zero configuration.
- Perfect for frontend development when you don't have a backend yet!
GitHub: github.com/typicode/json-server
Install globally:
npm install -g json-server
Or install locally:
npm install json-server --save-dev
Create a db.json
file:
{
"posts": [
{ "id": 1, "title": "First Post", "author": "John" },
{ "id": 2, "title": "Second Post", "author": "Jane" }
],
"comments": [
{ "id": 1, "body": "Great post!", "postId": 1 },
{ "id": 2, "body": "Nice work!", "postId": 2 }
],
"profile": {
"name": "John Doe"
}
}
Start the server:
json-server --watch db.json --port 3001
JSON Server automatically creates REST endpoints:
GET /posts
- Get all postsGET /posts/1
- Get post with id 1POST /posts
- Create a new postPUT /posts/1
- Update post with id 1PATCH /posts/1
- Partially update post with id 1DELETE /posts/1
- Delete post with id 1
Additional features:
GET /posts?_limit=10
- Limit resultsGET /posts?_sort=title&_order=asc
- Sort resultsGET /posts?title_like=react
- Search (case-insensitive)GET /posts?_embed=comments
- Include related data
Example: Fetching data
import { useState, useEffect } from 'react';
function Posts() {
const [posts, setPosts] = useState([]);
useEffect(() => {
fetch('http://localhost:3001/posts')
.then(response => response.json())
.then(data => setPosts(data));
}, []);
return (
<div>
{posts.map(post => (
<div key={post.id}>
<h3>{post.title}</h3>
<p>By: {post.author}</p>
</div>
))}
</div>
);
}
Example: Creating data
function CreatePost() {
const [title, setTitle] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
fetch('http://localhost:3001/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: title,
author: 'Anonymous'
})
})
.then(response => response.json())
.then(data => console.log('Created:', data));
};
return (
<form onSubmit={handleSubmit}>
<input
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Post title"
/>
<button type="submit">Create Post</button>
</form>
);
}
Custom port and host:
json-server --watch db.json --port 3001 --host 0.0.0.0
Add to package.json scripts:
{
"scripts": {
"server": "json-server --watch db.json --port 3001"
}
}
Then run:
npm run server
- Prototyping: Quick API for frontend development
- Testing: Mock data for testing components
- Learning: Practice API calls without backend setup
- Demo: Showcase apps with realistic data
- JSON is a data format for storing and transporting data.
- JSON Server creates a full REST API from a JSON file.
- Perfect for frontend development and prototyping.
- Supports all CRUD operations and advanced queries.
JSON Server makes frontend development a breeze! πβ¨
useEffect
is a React Hook that lets you perform side effects in function components.- Side effects are operations like data fetching, subscriptions, or manually changing the DOM.
- useEffect in React Docs
When to use:
- API calls, timers, subscriptions, DOM manipulation, etc.
useEffect(() => {
// Side effect code here
}, [dependencies]);
Parts:
- Effect function: The code that runs
- Dependency array: Controls when the effect runs
import { useEffect } from 'react';
function UserProfile() {
useEffect(() => {
console.log('Component mounted!');
// Fetch user data, set up subscriptions, etc.
}, []); // Empty array = run only once
return <div>User Profile</div>;
}
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('Count changed:', count);
// This runs every time count changes
}); // No dependency array = run every render
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
function UserPosts({ userId }) {
const [posts, setPosts] = useState([]);
useEffect(() => {
fetch(`/api/users/${userId}/posts`)
.then(response => response.json())
.then(data => setPosts(data));
}, [userId]); // Runs when userId changes
return <div>{posts.map(post => <div key={post.id}>{post.title}</div>)}</div>;
}
- Cleanup prevents memory leaks by cleaning up subscriptions, timers, etc.
Example: Timer with Cleanup
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(prev => prev + 1);
}, 1000);
// Cleanup function
return () => {
clearInterval(interval);
};
}, []); // Empty array = run once
return <div>Seconds: {seconds}</div>;
}
Example: API Subscription
function ChatRoom({ roomId }) {
useEffect(() => {
const subscription = subscribeToRoom(roomId);
return () => {
subscription.unsubscribe(); // Cleanup subscription
};
}, [roomId]);
return <div>Chat Room {roomId}</div>;
}
- Effect runs only once (on mount)
- Use for: Initial setup, one-time API calls
- Effect runs after every render
- Use carefully (can cause infinite loops)
- Effect runs when dependencies change
- Include all values from component scope that the effect uses
Example:
function SearchResults({ query, filters }) {
useEffect(() => {
searchAPI(query, filters);
}, [query, filters]); // Runs when query OR filters change
}
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
fetch('/api/users')
.then(response => response.json())
.then(data => {
setUsers(data);
setLoading(false);
})
.catch(error => {
console.error('Error:', error);
setLoading(false);
});
}, []);
if (loading) return <div>Loading...</div>;
return <div>{users.map(user => <div key={user.id}>{user.name}</div>)}</div>;
}
function WindowSize() {
const [size, setSize] = useState({ width: 0, height: 0 });
useEffect(() => {
const handleResize = () => {
setSize({ width: window.innerWidth, height: window.innerHeight });
};
window.addEventListener('resize', handleResize);
handleResize(); // Set initial size
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return <div>Window size: {size.width} x {size.height}</div>;
}
- Always include dependencies that the effect uses
- Use cleanup functions for subscriptions, timers, event listeners
- Split effects by purpose (don't put unrelated logic in one effect)
- Use multiple effects instead of one complex effect
- Be careful with objects/arrays in dependencies (use useCallback/useMemo if needed)
// β Missing dependency
useEffect(() => {
setCount(count + 1);
}, []); // Should include 'count'
// β Infinite loop
useEffect(() => {
setCount(count + 1);
}, [count]); // Creates infinite loop
// β
Correct way
useEffect(() => {
setCount(prev => prev + 1);
}, []); // Use functional update
- useEffect handles side effects in function components
- Dependency array controls when the effect runs
- Cleanup functions prevent memory leaks
- Use for: API calls, subscriptions, timers, DOM manipulation
Master useEffect to handle side effects like a pro! πβ¨
- You can use
useEffect
as many times as you want in a component. - Split effects by purpose: one for data fetching, one for subscriptions, etc.
Example:
useEffect(() => {
// Fetch data
}, []);
useEffect(() => {
// Set up event listener
return () => {
// Cleanup
};
}, []);
- React Router is a popular library for handling navigation and routing in React applications. It allows you to display different components based on the URL, create navigation menus, and manage browser history.
- React Router v6 is the latest major version (as of 2024).
- Routes determine which component is rendered for a given URL path.
- You use the
<Routes>
and<Route>
components fromreact-router-dom
.
Example:
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './Home';
import About from './About';
import Contact from './Contact';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</BrowserRouter>
);
}
- The
path
prop sets the URL, andelement
is the component to render.
- Use the
<Link>
component to navigate between routes without reloading the page (SPA behavior).
Example:
import { Link } from 'react-router-dom';
function Navbar() {
return (
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/contact">Contact</Link>
</nav>
);
}
- The
to
prop sets the destination path. Clicking aLink
updates the URL and renders the corresponding component.
- Use
<NavLink>
for navigation links that need to show an "active" style when the link matches the current URL.
Example:
import { NavLink } from 'react-router-dom';
function Navbar() {
return (
<nav>
<NavLink to="/" style={({ isActive }) => ({ fontWeight: isActive ? 'bold' : 'normal' })}>
Home
</NavLink>
<NavLink to="/about" className={({ isActive }) => isActive ? 'active-link' : undefined}>
About
</NavLink>
<NavLink to="/contact">
Contact
</NavLink>
</nav>
);
}
- You can use the
style
orclassName
prop to apply styles when the link is active. - The
isActive
argument tells you if the link matches the current route.
// App.js
import { BrowserRouter, Routes, Route, Link, NavLink } from 'react-router-dom';
function Home() {
return <h2>Home Page</h2>;
}
function About() {
return <h2>About Page</h2>;
}
function Contact() {
return <h2>Contact Page</h2>;
}
function Navbar() {
return (
<nav>
<NavLink to="/" end style={({ isActive }) => ({ color: isActive ? 'red' : 'black' })}>
Home
</NavLink>
{' | '}
<NavLink to="/about" style={({ isActive }) => ({ color: isActive ? 'red' : 'black' })}>
About
</NavLink>
{' | '}
<NavLink to="/contact" style={({ isActive }) => ({ color: isActive ? 'red' : 'black' })}>
Contact
</NavLink>
</nav>
);
}
function App() {
return (
<BrowserRouter>
<Navbar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</BrowserRouter>
);
}
- useNavigate is a React Router hook that lets you navigate to different routes in your app using JavaScript code (not just by clicking links).
- This is useful for redirecting after a form submission, button click, or as a result of some logic.
import { useNavigate } from 'react-router-dom';
function MyComponent() {
const navigate = useNavigate();
function handleClick() {
navigate('/about'); // Go to the /about page
}
return <button onClick={handleClick}>Go to About</button>;
}
- Calling
navigate('/about')
changes the URL and renders the corresponding route.
- You can pass options to
navigate
:replace: true
replaces the current entry in the history stack (like a redirect).navigate(-1)
goes back one page (like browser back button).
Example:
navigate('/login', { replace: true }); // Redirect to /login, replacing current page
navigate(-1); // Go back
import { useNavigate } from 'react-router-dom';
function LoginForm() {
const navigate = useNavigate();
function handleSubmit(e) {
e.preventDefault();
// ... authentication logic ...
navigate('/dashboard'); // Redirect to dashboard after login
}
return (
<form onSubmit={handleSubmit}>
<input type="text" placeholder="Username" />
<button type="submit">Login</button>
</form>
);
}
- Route parameters (params) let you capture dynamic values from the URL and use them in your components. They are useful for things like user profiles, product pages, etc.
- Use a colon (
:
) in thepath
to define a param.
Example:
<Routes>
<Route path="/users/:userId" element={<UserProfile />} />
</Routes>
- Here,
:userId
is a route parameter. URLs like/users/42
or/users/alice
will match.
- Use the
useParams
hook fromreact-router-dom
to access params inside your component.
Example:
import { useParams } from 'react-router-dom';
function UserProfile() {
const { userId } = useParams();
return <h2>User ID: {userId}</h2>;
}
- The
useParams
hook returns an object with all route params as strings.
<Route path="/posts/:postId/comments/:commentId" element={<Comment />} />
// In Comment component:
const { postId, commentId } = useParams();
- Add a
?
to make a param optional (React Router v6+):
<Route path="/users/:userId?" element={<UserProfile />} />
- For query strings like
?sort=asc&page=2
, use theuseSearchParams
hook.
Example:
import { useSearchParams } from 'react-router-dom';
function Products() {
const [searchParams, setSearchParams] = useSearchParams();
const sort = searchParams.get('sort');
const page = searchParams.get('page');
return <div>Sort: {sort}, Page: {page}</div>;
}
- You can also update search params with
setSearchParams
.
import { BrowserRouter, Routes, Route, useParams, useSearchParams } from 'react-router-dom';
function UserProfile() {
const { userId } = useParams();
return <h2>User ID: {userId}</h2>;
}
function Products() {
const [searchParams] = useSearchParams();
const sort = searchParams.get('sort') || 'none';
return <h2>Sort order: {sort}</h2>;
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/users/:userId" element={<UserProfile />} />
<Route path="/products" element={<Products />} />
</Routes>
</BrowserRouter>
);
}
- Always wrap your app in
<BrowserRouter>
(orHashRouter
for static hosting). - Use
<Routes>
and<Route>
for route definitions (v6+). - Use
<Link>
or<NavLink>
for navigation instead of<a>
tags to avoid full page reloads. - The
end
prop onNavLink
ensures exact matching for the root path.
- Handling unknown routes is important for user experience. In React Router, you can show a custom 404 page when no route matches the current URL.
- Use a
path="*"
route as the last<Route>
to catch all unmatched URLs.
Example:
import { BrowserRouter, Routes, Route } from 'react-router-dom';
function NotFound() {
return <h2>404 - Page Not Found</h2>;
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
- The
path="*"
route will match any URL that doesn't match a previous route, displaying theNotFound
component.
- You can add navigation links, images, or custom styles to your 404 page.
Example:
function NotFound() {
return (
<div style={{ textAlign: 'center', marginTop: '2rem' }}>
<h1>404</h1>
<p>Sorry, the page you are looking for does not exist.</p>
<Link to="/">Go Home</Link>
</div>
);
}
- Nested routes let you render child components inside parent components based on the URL structure. This is useful for layouts, dashboards, and sections with sub-pages.
- Use a parent
<Route>
with child<Route>
s inside. The parent component should render an<Outlet />
where child routes will appear.
Example:
import { BrowserRouter, Routes, Route, Outlet, Link } from 'react-router-dom';
function Dashboard() {
return (
<div>
<h2>Dashboard</h2>
<nav>
<Link to="profile">Profile</Link> | <Link to="settings">Settings</Link>
</nav>
<Outlet /> {/* Child routes render here */}
</div>
);
}
function Profile() {
return <h3>Profile Page</h3>;
}
function Settings() {
return <h3>Settings Page</h3>;
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/dashboard" element={<Dashboard />}>
<Route index element={<DashboardHome />} />
<Route path="profile" element={<Profile />} />
<Route path="settings" element={<Settings />} />
</Route>
<Route path="/" element={<Home />} />
</Routes>
</BrowserRouter>
);
}
- Visiting
/dashboard/profile
or/dashboard/settings
will render the corresponding child component insideDashboard
.
- Use
index
to render a default child route when the parent path is matched exactly.
Example:
<Route path="/dashboard" element={<Dashboard />}>
<Route index element={<DashboardHome />} />
<Route path="profile" element={<Profile />} />
</Route>
- Now
/dashboard
showsDashboardHome
by default.
- Use relative paths in
Link
(e.g.,to="profile"
) for child routes.
import { BrowserRouter, Routes, Route, Outlet, Link } from 'react-router-dom';
function Dashboard() {
return (
<div>
<h2>Dashboard</h2>
<nav>
<Link to="profile">Profile</Link> | <Link to="settings">Settings</Link>
</nav>
<Outlet />
</div>
);
}
function DashboardHome() {
return <h3>Welcome to your dashboard!</h3>;
}
function Profile() {
return <h3>Profile Page</h3>;
}
function Settings() {
return <h3>Settings Page</h3>;
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/dashboard" element={<Dashboard />}>
<Route index element={<DashboardHome />} />
<Route path="profile" element={<Profile />} />
<Route path="settings" element={<Settings />} />
</Route>
<Route path="/" element={<h2>Home</h2>} />
</Routes>
</BrowserRouter>
);
}
useCallback
memoizes a function so it only changes if its dependencies change.- Useful for optimizing performance, especially when passing callbacks to child components.
Example:
import { useCallback, useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount(c => c + 1);
}, []);
return <button onClick={increment}>Count: {count}</button>;
}
- React supports all common DOM events:
onClick
,onChange
,onSubmit
,onMouseOver
, etc. - Event handlers are camelCase and receive an event object.
onClick Example:
function Button() {
const handleClick = () => {
alert('Button clicked!');
};
return <button onClick={handleClick}>Click me</button>;
}
onChange Example:
function Input() {
const [value, setValue] = useState('');
return (
<input value={value} onChange={e => setValue(e.target.value)} />
);
}
onSubmit Example:
function Form() {
const handleSubmit = e => {
e.preventDefault();
// Do something
};
return (
<form onSubmit={handleSubmit}>
<button type="submit">Submit</button>
</form>
);
}
- Use multiple
useEffect
s for different side effects. - Handle errors and loading for a better user experience.
- Custom hooks help you reuse logic.
useCallback
optimizes performance for callbacks.- React events are camelCase and easy to use.
Master these patterns for robust, maintainable React apps! π
- useLocation is a React Router hook that lets you access information about the current URL/location in your app.
- This is useful for reading the current path, search params, hash, or state passed during navigation.
import { useLocation } from 'react-router-dom';
function ShowLocation() {
const location = useLocation();
return (
<div>
<p>Current pathname: {location.pathname}</p>
<p>Search string: {location.search}</p>
<p>Hash: {location.hash}</p>
<p>State: {JSON.stringify(location.state)}</p>
</div>
);
}
- The
location
object contains:pathname
: The current path (e.g.,"/about"
)search
: The query string (e.g.,"?sort=asc"
)hash
: The hash fragment (e.g.,"#section1"
)state
: Any state passed with navigationkey
: Unique location key
import { useLocation } from 'react-router-dom';
function SectionNav() {
const location = useLocation();
return (
<nav>
<a href="#section1" style={{ fontWeight: location.hash === '#section1' ? 'bold' : 'normal' }}>Section 1</a>
<a href="#section2" style={{ fontWeight: location.hash === '#section2' ? 'bold' : 'normal' }}>Section 2</a>
</nav>
);
}
import { useLocation, useNavigate } from 'react-router-dom';
function Sender() {
const navigate = useNavigate();
return <button onClick={() => navigate('/target', { state: { from: 'Sender' } })}>Go</button>;
}
function Target() {
const location = useLocation();
return <div>Arrived from: {location.state?.from}</div>;
}
- index.js files are commonly used in folders to centralize and simplify imports/exports.
- They allow you to re-export multiple modules from a single entry point, making imports cleaner and more maintainable.
Suppose you have a folder structure like this:
/components
|-- Button.js
|-- Card.js
|-- Navbar.js
|-- index.js
Button.js
export default function Button() { /* ... */ }
Card.js
export default function Card() { /* ... */ }
Navbar.js
export default function Navbar() { /* ... */ }
index.js (re-exporting all components)
export { default as Button } from './Button';
export { default as Card } from './Card';
export { default as Navbar } from './Navbar';
- Now you can import all components from the folder, not individual files:
import { Button, Card, Navbar } from './components';
- This is much cleaner, especially as your project grows.
- You can also re-export named exports from multiple files:
utils/math.js
export function add(a, b) { return a + b; }
export function subtract(a, b) { return a - b; }
utils/string.js
export function capitalize(str) { /* ... */ }
export function toLower(str) { /* ... */ }
utils/index.js
export * from './math';
export * from './string';
Now you can do:
import { add, subtract, capitalize } from './utils';
- index.js is automatically resolved by import statements targeting the folder.
- You can use
index.ts
for TypeScript projects. - This pattern is great for organizing components, hooks, utilities, and contexts.
- Avoid circular dependencies when re-exporting from multiple files.
- Centralizing your routes in a dedicated folder makes your app easier to maintain, scale, and organize, especially for larger projects.
- You can define all your route components and route definitions in one place, then import them into your main
App.js
ormain.jsx
.
/src
/components
/pages
/routes
|-- AppRoutes.js
|-- index.js
App.js
routes/AppRoutes.js
import { Routes, Route } from 'react-router-dom';
import Home from '../pages/Home';
import About from '../pages/About';
import Dashboard from '../pages/Dashboard';
import NotFound from '../pages/NotFound';
function AppRoutes() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/dashboard/*" element={<Dashboard />} />
<Route path="*" element={<NotFound />} />
</Routes>
);
}
export default AppRoutes;
routes/index.js
export { default as AppRoutes } from './AppRoutes';
App.js
import { BrowserRouter } from 'react-router-dom';
import { AppRoutes } from './routes';
function App() {
return (
<BrowserRouter>
<AppRoutes />
</BrowserRouter>
);
}
export default App;
- Keeps your main
App.js
clean and focused. - Makes it easy to add, remove, or update routes in one place.
- Encourages separation of concerns and better project structure.