Complete React Documentation
Complete React Documentation
Table of Contents
1. Introduction to React
2. Getting Started
3. JSX Fundamentals
4. Components
5. Props
6. State Management
7. Event Handling
8. Conditional Rendering
9. Lists and Keys
Introduction to React
React is a JavaScript library for building user interfaces, particularly web applications. Created by
Facebook (now Meta) in 2013, React has become one of the most popular frontend frameworks due to
its component-based architecture, virtual DOM, and declarative programming style.
Key Features
Component-Based Architecture: React applications are built using reusable components that manage
their own state and can be composed to create complex UIs.
Virtual DOM: React creates a virtual representation of the DOM in memory, allowing for efficient
updates by comparing the virtual DOM with the actual DOM and updating only what has changed.
Declarative Programming: You describe what the UI should look like for any given state, and React
handles the how of updating the DOM.
Unidirectional Data Flow: Data flows down from parent to child components through props, making
applications more predictable and easier to debug.
Rich Ecosystem: React has a vast ecosystem of libraries, tools, and community support.
Getting Started
Prerequisites
Before working with React, you should have a solid understanding of:
Installation Methods
bash
bash
Project Structure
A typical React project structure looks like this:
my-app/
├── public/
│ ├── index.html
│ └── favicon.ico
├── src/
│ ├── components/
│ ├── hooks/
│ ├── utils/
│ ├── App.js
│ ├── App.css
│ ├── index.js
│ └── index.css
├── package.json
└── README.md
JSX Fundamentals
JSX (JavaScript XML) is a syntax extension for JavaScript that allows you to write HTML-like code within
JavaScript. It's transpiled to regular JavaScript function calls.
jsx
// JSX element
const element = <h1>Hello, World!</h1>;
jsx
// Wrong
return (
<h1>Title</h1>
<p>Content</p>
);
// Correct
return (
<div>
<h1>Title</h1>
<p>Content</p>
</div>
);
// Using Fragment
return (
<>
<h1>Title</h1>
<p>Content</p>
</>
);
jsx
// HTML
<div class="container" tabindex="1"></div>
// JSX
<div className="container" tabIndex="1"></div>
jsx
jsx
Components
Components are the building blocks of React applications. They are reusable pieces of UI that can have
their own state and logic.
Function Components
Function components are the modern way to create components in React. They are simpler and use
hooks for state and lifecycle management.
jsx
jsx
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Component Composition
Components can contain other components, allowing you to build complex UIs from simple building
blocks.
jsx
function App() {
return (
<div>
<Header />
<MainContent />
<Footer />
</div>
);
}
function Header() {
return (
<header>
<h1>My Website</h1>
<Navigation />
</header>
);
}
function Navigation() {
return (
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
);
}
Props
Props (properties) are how you pass data from parent components to child components. They are read-
only and help make components reusable.
jsx
// Parent component
function App() {
return (
<div>
<UserCard name="Alice" age={30} email="[email protected]" />
<UserCard name="Bob" age={25} email="[email protected]" />
</div>
);
}
// Child component
function UserCard(props) {
return (
<div className="user-card">
<h2>{props.name}</h2>
<p>Age: {props.age}</p>
<p>Email: {props.email}</p>
</div>
);
}
Props Destructuring
You can destructure props for cleaner code:
jsx
Default Props
You can provide default values for props:
jsx
function Button({ text, type = 'button', onClick }) {
return (
<button type={type} onClick={onClick}>
{text}
</button>
);
}
jsx
UserCard.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number.isRequired,
email: PropTypes.string.isRequired
};
Children Prop
The special children prop allows you to pass elements between component tags:
jsx
function Card({ children, title }) {
return (
<div className="card">
<h2>{title}</h2>
<div className="card-content">
{children}
</div>
</div>
);
}
// Usage
function App() {
return (
<Card title="Welcome">
<p>This is the card content</p>
<button>Click me</button>
</Card>
);
}
State Management
State represents data that can change over time. In function components, we use the useState hook to
manage state.
useState Hook
jsx
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<h2>Count: {count}</h2>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
}
jsx
function UserProfile() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [age, setAge] = useState(0);
return (
<div>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Name"
/>
<input
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="number"
value={age}
onChange={(e) => setAge(parseInt(e.target.value))}
placeholder="Age"
/>
</div>
);
}
jsx
function UserProfile() {
const [user, setUser] = useState({
name: '',
email: '',
age: 0
});
return (
<div>
<input
value={user.name}
onChange={(e) => updateUser('name', e.target.value)}
placeholder="Name"
/>
<input
value={user.email}
onChange={(e) => updateUser('email', e.target.value)}
placeholder="Email"
/>
<input
type="number"
value={user.age}
onChange={(e) => updateUser('age', parseInt(e.target.value))}
placeholder="Age"
/>
</div>
);
}
jsx
function TodoList() {
const [todos, setTodos] = useState([ ]);
const [inputValue, setInputValue] = useState('');
return (
<div>
<input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="Add a todo"
/>
<button onClick={addTodo}>Add</button>
<ul>
{todos.map(todo => (
<li key={todo.id}>
<span
style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
onClick={() => toggleTodo(todo.id)}
>
{todo.text}
</span>
<button onClick={() => deleteTodo(todo.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}
Event Handling
React uses SyntheticEvents, which are wrappers around native events that provide consistent behavior
across different browsers.
jsx
function Button() {
const handleClick = (event) => {
console.log('Button clicked!', event);
};
jsx
function FormExample() {
const [formData, setFormData] = useState({
name: '',
email: ''
});
return (
<form onSubmit={handleSubmit}>
<input
name="name"
value={formData.name}
onChange={handleInputChange}
onKeyPress={handleKeyPress}
placeholder="Name"
/>
<input
name="email"
value={formData.email}
onChange={handleInputChange}
placeholder="Email"
/>
<button type="submit">Submit</button>
</form>
);
}
jsx
function ItemList() {
const items = ['Apple', 'Banana', 'Cherry'];
return (
<ul>
{items.map((item, index) => (
<li key={index} onClick={() => handleItemClick(item, index)}>
{item}
</li>
))}
</ul>
);
}
Conditional Rendering
React allows you to conditionally render components or elements based on certain conditions.
Using if Statements
jsx
jsx
function UserGreeting({ user }) {
return (
<h1>
{user ? `Welcome back, ${user.name}!` : 'Please sign in.'}
</h1>
);
}
jsx
Switch-Case Pattern
jsx
function StatusMessage({ status }) {
const renderMessage = () => {
switch (status) {
case 'loading':
return <div>Loading...</div>;
case 'success':
return <div className="success">Success!</div>;
case 'error':
return <div className="error">Something went wrong.</div>;
default:
return null;
}
};
return renderMessage();
}
jsx
function ShoppingList() {
const items = ['Milk', 'Bread', 'Eggs', 'Butter'];
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
}
jsx
function UserList() {
const users = [
{ id: 1, name: 'Alice', email: '[email protected]' },
{ id: 2, name: 'Bob', email: '[email protected]' },
{ id: 3, name: 'Charlie', email: '[email protected]' }
];
return (
<div>
{users.map(user => (
<div key={user.id} className="user-card">
<h3>{user.name}</h3>
<p>{user.email}</p>
</div>
))}
</div>
);
}
jsx
// Good
{items.map(item => <Item key={item.id} data={item} />)}
Keys Must Be Unique Among Siblings: Keys only need to be unique among sibling elements, not
globally.
React Hooks
Hooks are functions that let you "hook into" React features like state and lifecycle methods from
function components.
useState Hook
Already covered in the State Management section, useState allows you to add state to function
components.
useEffect Hook
useEffect lets you perform side effects in function components. It serves the same purpose as
componentDidMount, componentDidUpdate, and componentWillUnmount combined.
jsx
useEffect(() => {
const fetchUser = async () => {
setLoading(true);
try {
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
setUser(userData);
} catch (error) {
console.error('Error fetching user:', error);
} finally {
setLoading(false);
}
};
fetchUser();
}, [userId]); // Effect depends on userId
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
useEffect Cleanup
jsx
function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCount(prev => prev + 1);
}, 1000);
// Cleanup function
return () => {
clearInterval(interval);
};
}, [ ]); // Empty dependency array means this effect runs once
useContext Hook
useContext allows you to consume context values without nesting.
jsx
import React, { createContext, useContext, useState } from 'react';
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
function ThemedButton() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<button
className={`btn-${theme}`}
onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
>
Switch to {theme === 'light' ? 'dark' : 'light'} theme
</button>
);
}
useReducer Hook
useReducer is an alternative to useState for managing complex state logic.
jsx
import React, { useReducer } from 'react';
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
<button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
</div>
);
}
Custom Hooks
Custom hooks are JavaScript functions that start with "use" and can call other hooks.
jsx
// Custom hook for local storage
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
return initialValue;
}
});
// Usage
function App() {
const [name, setName] = useLocalStorage('name', '');
return (
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Your name"
/>
);
}
jsx
import React, { useState, useMemo, useCallback } from 'react';
return (
<div>
<p>Expensive value: {expensiveValue}</p>
<p>Count: {count}</p>
<button onClick={handleClick}>Increment</button>
</div>
);
}
Component Lifecycle
While function components don't have traditional lifecycle methods, useEffect can replicate their
behavior.
jsx
function MyComponent() {
// ComponentDidMount equivalent
useEffect(() => {
console.log('Component mounted');
}, [ ]);
// ComponentDidUpdate equivalent
useEffect(() => {
console.log('Component updated');
});
// ComponentWillUnmount equivalent
useEffect(() => {
return () => {
console.log('Component will unmount');
};
}, [ ]);
Context API
The Context API provides a way to pass data through the component tree without having to pass props
down manually at every level.
jsx
import React, { createContext, useContext, useState } from 'react';
// Create context
const UserContext = createContext();
// Provider component
function UserProvider({ children }) {
const [user, setUser] = useState(null);
return (
<UserContext.Provider value={{ user, login, logout }}>
{children}
</UserContext.Provider>
);
}
if (user) {
return (
<div>
<span>Welcome, {user.name}!</span>
<button onClick={logout}>Logout</button>
</div>
);
}
return (
<button onClick={() => login({ name: 'John Doe', id: 1 })}>
Login
</button>
);
}
function App() {
return (
<UserProvider>
<div>
<h1>My App</h1>
<LoginButton />
</div>
</UserProvider>
);
}
Error Boundaries
Error boundaries are React components that catch JavaScript errors anywhere in their child component
tree.
jsx
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null, errorInfo: null };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
this.setState({
error: error,
errorInfo: errorInfo
});
}
render() {
if (this.state.hasError) {
return (
<div>
<h2>Something went wrong.</h2>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.error && this.state.error.toString()}
<br />
{this.state.errorInfo.componentStack}
</details>
</div>
);
}
return this.props.children;
}
}
// Usage
function App() {
return (
<ErrorBoundary>
<Header />
<MainContent />
<Footer />
</ErrorBoundary>
);
}
Performance Optimization
React.memo
React.memo is a higher-order component that memoizes the result of a component.
jsx
return (
<div>
<h3>{data.title}</h3>
<button onClick={onClick}>Click me</button>
</div>
);
});
jsx
import React, { Suspense, lazy } from 'react';
function App() {
return (
<div>
<h1>My App</h1>
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
</div>
);
}
jsx
function App() {
return (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</Suspense>
</Router>
);
}
jsx
function ContactForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
message: '',
category: 'general',
newsletter: false
});
return (
<form onSubmit={handleSubmit}>
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
placeholder="Your Name"
required
/>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
placeholder="Your Email"
required
/>
<textarea
name="message"
value={formData.message}
onChange={handleChange}
placeholder="Your Message"
rows="4"
required
/>
<select
name="category"
value={formData.category}
onChange={handleChange}
>
<option value="general">General</option>
<option value="support">Support</option>
<option value="billing">Billing</option>
</select>
<label>
<input
type="checkbox"
name="newsletter"
checked={formData.newsletter}
onChange={handleChange}
/>
Subscribe to newsletter
</label>
<button type="submit">Submit</button>
</form>
);
}
Form Validation
jsx
function ValidatedForm() {
const [formData, setFormData] = useState({
email: '',
password: '',
confirmPassword: ''
});
if (!formData.email) {
newErrors.email = 'Email is required';
} else if (!/\S+@\S+\.\S+/.test(formData.email)) {
newErrors.email = 'Email is invalid';
}
if (!formData.password) {
newErrors.password = 'Password is required';
} else if (formData.password.length < 6) {
newErrors.password = 'Password must be at least 6 characters';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
return (
<form onSubmit={handleSubmit}>
<div>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
placeholder="Email"
/>
{errors.email && <span className="error">{errors.email}</span>}
</div>
<div>
<input
type="password"
name="password"
value={formData.password}
onChange={handleChange}
placeholder="Password"
/>
{errors.password && <span className="error">{errors.password}</span>}
</div>
<div>
<input
type="password"
name="confirmPassword"
value={formData.confirmPassword}
onChange={handleChange}
placeholder="Confirm Password"
/>
{errors.confirmPassword && <span className="error">{errors.confirmPassword}</span>}
</div>
<button type="submit">Register</button>
</form>
);
}
jsx
import React, { useRef } from 'react';
function UncontrolledForm() {
const nameRef = useRef();
const emailRef = useRef();
const fileRef = useRef();
return (
<form onSubmit={handleSubmit}>
<input
ref={nameRef}
type="text"
placeholder="Name"
defaultValue="John Doe"
/>
<input
ref={emailRef}
type="email"
placeholder="Email"
/>
<input
ref={fileRef}
type="file"
/>
<button type="submit">Submit</button>
</form>
);
}
Routing
React Router is the standard library for routing in React applications.
Basic Setup
bash
npm install react-router-dom
jsx
import React from 'react';
import { BrowserRouter as Router, Routes, Route, Link, Navigate } from 'react-router-dom';
function App() {
return (
<Router>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/contact">Contact</Link></li>
<li><Link to="/users">Users</Link></li>
</ul>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
<Route path="/users" element={<Users />} />
<Route path="/users/:id" element={<UserDetail />} />
<Route path="/admin/*" element={<AdminRoutes />} />
<Route path="*" element={<NotFound />} />
</Routes>
</Router>
);
}
function Home() {
return <h2>Home Page</h2>;
}
function About() {
return <h2>About Page</h2>;
}
function Contact() {
return <h2>Contact Page</h2>;
}
jsx
import { useParams, useSearchParams, useNavigate } from 'react-router-dom';
function UserDetail() {
const { id } = useParams();
const [searchParams, setSearchParams] = useSearchParams();
const navigate = useNavigate();
return (
<div>
<h2>User Detail - ID: {id}</h2>
<button onClick={goBack}>Go Back</button>
<button onClick={goToUsers}>Go to Users</button>
<div>
<button
className={tab === 'profile' ? 'active' : ''}
onClick={() => handleTabChange('profile')}
>
Profile
</button>
<button
className={tab === 'settings' ? 'active' : ''}
onClick={() => handleTabChange('settings')}
>
Settings
</button>
</div>
Protected Routes
jsx
if (!user) {
return <Navigate to="/login" replace />;
}
return children;
}
function App() {
return (
<Router>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/dashboard" element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
} />
</Routes>
</Router>
);
}
Nested Routes
jsx
function AdminRoutes() {
return (
<div>
<h2>Admin Panel</h2>
<nav>
<Link to="/admin/users">Users</Link>
<Link to="/admin/products">Products</Link>
<Link to="/admin/orders">Orders</Link>
</nav>
<Routes>
<Route path="users" element={<AdminUsers />} />
<Route path="products" element={<AdminProducts />} />
<Route path="orders" element={<AdminOrders />} />
<Route index element={<AdminDashboard />} />
</Routes>
</div>
);
}
bash
jsx
// store/userSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
// store/store.js
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './userSlice';
// App.js
import { Provider } from 'react-redux';
import { store } from './store/store';
function App() {
return (
<Provider store={store}>
<UserProfile />
</Provider>
);
}
function UserProfile() {
const { data: user, loading, error } = useSelector(state => state.user);
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchUser(1));
}, [dispatch]);
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
<button onClick={() => dispatch(clearUser())}>
Clear User
</button>
</div>
);
}
bash
jsx
import { create } from 'zustand';
useEffect(() => {
fetchUser(1);
}, [fetchUser]);
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
<button onClick={clearUser}>Clear User</button>
</div>
);
}
Testing
bash
jsx
// Button.test.js
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom';
import Button from './Button';
await user.click(button);
expect(handleClick).toHaveBeenCalledTimes(1);
});
// Testing forms
// ContactForm.test.js
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import ContactForm from './ContactForm';
// Testing hooks
// useCounter.test.js
import { renderHook, act } from '@testing-library/react';
import useCounter from './useCounter';
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});
jsx
// ApiComponent.test.js
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import ApiComponent from './ApiComponent';
// Mock fetch
global.fetch = jest.fn();
beforeEach(() => {
fetch.mockClear();
});
Best Practices
Component Organization
Single Responsibility Principle: Each component should have one clear purpose.
jsx
return (
<div>
{/* Complex UI mixing different concerns */}
</div>
);
}
File Organization:
src/
├── components/
│ ├── common/
│ │ ├── Button/
│ │ │ ├── Button.js
│ │ │ ├── Button.test.js
│ │ │ └── Button.css
│ │ └── Modal/
│ └── pages/
│ ├── Home/
│ └── UserProfile/
├── hooks/
├── context/
├── utils/
└── services/
Naming Conventions
Components: Use PascalCase
jsx
function UserProfile() { }
function ShoppingCart() { }
jsx
jsx
jsx
<Button isLoading hasError canSubmit />
Props Patterns
Prop Spreading: Use with caution
jsx
jsx
function Button({
children,
type = 'button',
variant = 'primary',
disabled = false,
...rest
}) {
return (
<button
type={type}
className={`btn btn-${variant}`}
disabled={disabled}
{...rest}
>
{children}
</button>
);
}
State Management Best Practices
Keep State Close: Don't lift state higher than necessary
jsx
jsx
// Bad
const addItem = (newItem) => {
items.push(newItem);
setItems(items);
};
// Good
const addItem = (newItem) => {
setItems(prevItems => [...prevItems, newItem]);
};
// For objects
const updateUser = (updates) => {
setUser(prevUser => ({ ...prevUser, ...updates }));
};
jsx
// Bad
function MyComponent() {
return (
<ChildComponent
style={{ margin: 10 }}
onClick={() => console.log('clicked')}
/>
);
}
// Good
const styles = { margin: 10 };
function MyComponent() {
const handleClick = useCallback(() => {
console.log('clicked');
}, [ ]);
return (
<ChildComponent
style={styles}
onClick={handleClick}
/>
);
}
jsx
// Bad
{items.map((item, index) => (
<Item key={index} data={item} />
))}
// Good
{items.map(item => (
<Item key={item.id} data={item} />
))}
Error Handling
Graceful Error Handling: Always handle potential errors
jsx
useEffect(() => {
const fetchUser = async () => {
try {
setLoading(true);
setError(null);
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) {
throw new Error(`Failed to fetch user: ${response.status}`);
}
fetchUser();
}, [userId]);
Advanced Patterns
jsx
function DataFetcher({ url, children }) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
setLoading(true);
const response = await fetch(url);
const result = await response.json();
setData(result);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
// Usage
function App() {
return (
<DataFetcher url="/api/users">
{({ data, loading, error }) => {
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<ul>
{data?.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}}
</DataFetcher>
);
}
jsx
function withAuth(WrappedComponent) {
return function AuthenticatedComponent(props) {
const { user } = useUser();
if (!user) {
return <div>Please log in to access this page.</div>;
}
// Usage
const ProtectedProfile = withAuth(UserProfile);
jsx
function Tabs({ children, defaultTab }) {
const [activeTab, setActiveTab] = useState(defaultTab);
return (
<div className="tabs">
{React.Children.map(children, child => {
return React.cloneElement(child, { activeTab, setActiveTab });
})}
</div>
);
}
// Usage
function App() {
return (
<Tabs defaultTab={0}>
<TabList>
<Tab>Profile</Tab>
<Tab>Settings</Tab>
<Tab>Billing</Tab>
</TabList>
<TabPanels>
<TabPanel><div>Profile Content</div></TabPanel>
<TabPanel><div>Settings Content</div></TabPanel>
<TabPanel><div>Billing Content</div></TabPanel>
</TabPanels>
</Tabs>
);
}
Portal Pattern
jsx
import { createPortal } from 'react-dom';
return createPortal(
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
<button className="modal-close" onClick={onClose}>×</button>
{children}
</div>
</div>,
document.body
);
}
// Usage
function App() {
const [showModal, setShowModal] = useState(false);
return (
<div>
<button onClick={() => setShowModal(true)}>Open Modal</button>
<Modal isOpen={showModal} onClose={() => setShowModal(false)}>
<h2>Modal Content</h2>
<p>This modal is rendered in a portal!</p>
</Modal>
</div>
);
}
jsx
const FancyButton = React.forwardRef(function FancyButton(props, ref) {
return (
<button className="fancy-button" ref={ref} {...props}>
{props.children}
</button>
);
});
// Usage
function App() {
const buttonRef = useRef();
return (
<div>
<FancyButton ref={buttonRef}>Click me</FancyButton>
<button onClick={focusButton}>Focus the fancy button</button>
</div>
);
}
This comprehensive React documentation covers all the essential concepts, patterns, and best practices
you need to build modern React applications. From basic components and state management to
advanced patterns and performance optimization, this guide provides practical examples and real-world
use cases that you can reference and build upon in your React projects.