Loading...
Loading...
Comprehensive React development with hooks, components, state management, context, effects, and performance optimization based on official React documentation
npx skill4agent add manutej/luxor-claude-marketplace react-developmentfunction Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
// Arrow function syntax
const Greeting = ({ name, age }) => {
return (
<div>
<h2>{name}</h2>
<p>Age: {age}</p>
</div>
);
};function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}// Embedding expressions
const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;
// JSX attributes
const image = <img src={user.avatarUrl} alt={user.name} />;
// JSX children
const container = (
<div>
<h1>Welcome</h1>
<p>Get started with React</p>
</div>
);
// Conditional rendering
const greeting = (
<div>
{isLoggedIn ? <UserGreeting /> : <GuestGreeting />}
</div>
);
// Lists and keys
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>{number}</li>
);function Product({ name, price, inStock }) {
return (
<div className="product">
<h3>{name}</h3>
<p>${price}</p>
{inStock ? <span>In Stock</span> : <span>Out of Stock</span>}
</div>
);
}
// Usage
<Product name="Laptop" price={999} inStock={true} />function Card({ title, children }) {
return (
<div className="card">
<h2>{title}</h2>
<div className="card-content">
{children}
</div>
</div>
);
}
// Usage
<Card title="Welcome">
<p>This is the card content</p>
<button>Click me</button>
</Card>function Button({ text = 'Click me', variant = 'primary' }) {
return <button className={variant}>{text}</button>;
}import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<button onClick={() => setCount(count - 1)}>Decrement</button>
<button onClick={() => setCount(0)}>Reset</button>
</div>
);
}import { useState } from 'react';
function Form() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
console.log({ name, email });
};
return (
<form onSubmit={handleSubmit}>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Name"
/>
<input
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
type="email"
/>
<button type="submit">Submit</button>
</form>
);
}function UserProfile() {
const [user, setUser] = useState({
name: '',
age: 0,
email: ''
});
const updateField = (field, value) => {
setUser(prev => ({
...prev,
[field]: value
}));
};
return (
<div>
<input
value={user.name}
onChange={(e) => updateField('name', e.target.value)}
/>
<input
type="number"
value={user.age}
onChange={(e) => updateField('age', parseInt(e.target.value))}
/>
<input
type="email"
value={user.email}
onChange={(e) => updateField('email', e.target.value)}
/>
</div>
);
}function TodoList() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
const addTodo = () => {
setTodos(prev => [...prev, { id: Date.now(), text: input }]);
setInput('');
};
const removeTodo = (id) => {
setTodos(prev => prev.filter(todo => todo.id !== id));
};
return (
<div>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button onClick={addTodo}>Add</button>
<ul>
{todos.map(todo => (
<li key={todo.id}>
{todo.text}
<button onClick={() => removeTodo(todo.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}import { useState, useEffect } from 'react';
function DocumentTitle() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
return (
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
);
}function UserData({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let cancelled = false;
async function fetchUser() {
try {
setLoading(true);
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
if (!cancelled) {
setUser(data);
setError(null);
}
} catch (err) {
if (!cancelled) {
setError(err.message);
}
} finally {
if (!cancelled) {
setLoading(false);
}
}
}
fetchUser();
return () => {
cancelled = true;
};
}, [userId]);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return <div>{user?.name}</div>;
}function WindowSize() {
const [size, setSize] = useState({
width: window.innerWidth,
height: window.innerHeight
});
useEffect(() => {
function handleResize() {
setSize({
width: window.innerWidth,
height: window.innerHeight
});
}
window.addEventListener('resize', handleResize);
// Cleanup function
return () => {
window.removeEventListener('resize', handleResize);
};
}, []); // Empty dependency array = run once on mount
return <div>{size.width} x {size.height}</div>;
}function Timer() {
const [seconds, setSeconds] = useState(0);
const [isRunning, setIsRunning] = useState(false);
useEffect(() => {
if (!isRunning) return;
const interval = setInterval(() => {
setSeconds(s => s + 1);
}, 1000);
return () => clearInterval(interval);
}, [isRunning]);
return (
<div>
<p>Seconds: {seconds}</p>
<button onClick={() => setIsRunning(!isRunning)}>
{isRunning ? 'Pause' : 'Start'}
</button>
<button onClick={() => setSeconds(0)}>Reset</button>
</div>
);
}import { createContext, useContext, useState } from 'react';
const ThemeContext = createContext('light');
function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={theme}>
<Toolbar />
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Toggle Theme
</button>
</ThemeContext.Provider>
);
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return (
<button className={theme}>
I am styled by {theme} theme
</button>
);
}const ThemeContext = createContext('light');
const UserContext = createContext(null);
function App() {
const [theme, setTheme] = useState('light');
const [currentUser, setCurrentUser] = useState({ name: 'John', role: 'admin' });
return (
<ThemeContext.Provider value={theme}>
<UserContext.Provider value={currentUser}>
<Dashboard />
</UserContext.Provider>
</ThemeContext.Provider>
);
}
function Dashboard() {
const theme = useContext(ThemeContext);
const user = useContext(UserContext);
return (
<div className={theme}>
<h1>Welcome, {user.name}</h1>
<p>Role: {user.role}</p>
</div>
);
}import { useReducer } from 'react';
function counterReducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
case 'reset':
return { count: 0 };
default:
throw new Error(`Unknown action: ${action.type}`);
}
}
function Counter() {
const [state, dispatch] = useReducer(counterReducer, { count: 0 });
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>
);
}function tasksReducer(tasks, action) {
switch (action.type) {
case 'added': {
return [...tasks, {
id: action.id,
text: action.text,
done: false
}];
}
case 'changed': {
return tasks.map(t => {
if (t.id === action.task.id) {
return action.task;
} else {
return t;
}
});
}
case 'deleted': {
return tasks.filter(t => t.id !== action.id);
}
default: {
throw Error('Unknown action: ' + action.type);
}
}
}
function TaskApp() {
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
function handleAddTask(text) {
dispatch({
type: 'added',
id: nextId++,
text: text,
});
}
function handleChangeTask(task) {
dispatch({
type: 'changed',
task: task
});
}
function handleDeleteTask(taskId) {
dispatch({
type: 'deleted',
id: taskId
});
}
return (
<>
<h1>Prague itinerary</h1>
<AddTask onAddTask={handleAddTask} />
<TaskList
tasks={tasks}
onChangeTask={handleChangeTask}
onDeleteTask={handleDeleteTask}
/>
</>
);
}
let nextId = 3;
const initialTasks = [
{ id: 0, text: 'Visit Kafka Museum', done: true },
{ id: 1, text: 'Watch a puppet show', done: false },
{ id: 2, text: 'Lennon Wall pic', done: false }
];import { useMemo, useState } from 'react';
function ProductList({ products, category }) {
const [sortOrder, setSortOrder] = useState('asc');
const filteredAndSortedProducts = useMemo(() => {
console.log('Filtering and sorting products...');
const filtered = products.filter(p => p.category === category);
return filtered.sort((a, b) => {
if (sortOrder === 'asc') {
return a.price - b.price;
}
return b.price - a.price;
});
}, [products, category, sortOrder]);
return (
<div>
<button onClick={() => setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc')}>
Sort: {sortOrder}
</button>
<ul>
{filteredAndSortedProducts.map(product => (
<li key={product.id}>{product.name} - ${product.price}</li>
))}
</ul>
</div>
);
}function SearchResults({ query }) {
const searchOptions = useMemo(() => ({
query,
limit: 10,
caseSensitive: false
}), [query]);
// searchOptions object only recreated when query changes
const results = useSearch(searchOptions);
return <ResultsList results={results} />;
}import { useCallback, useState } from 'react';
function ProductPage({ productId }) {
const [items, setItems] = useState([]);
const handleAddToCart = useCallback(() => {
setItems(prevItems => [...prevItems, productId]);
}, [productId]);
return <AddToCartButton onAdd={handleAddToCart} />;
}
// Memoized child component
const AddToCartButton = memo(({ onAdd }) => {
console.log('Button rendered');
return <button onClick={onAdd}>Add to Cart</button>;
});function TodoList() {
const [todos, setTodos] = useState(initialTodos);
const handleToggle = useCallback((id) => {
setTodos(prevTodos =>
prevTodos.map(todo =>
todo.id === id ? { ...todo, done: !todo.done } : todo
)
);
}, []);
const handleDelete = useCallback((id) => {
setTodos(prevTodos => prevTodos.filter(todo => todo.id !== id));
}, []);
return (
<ul>
{todos.map(todo => (
<TodoItem
key={todo.id}
todo={todo}
onToggle={handleToggle}
onDelete={handleDelete}
/>
))}
</ul>
);
}import { useRef } from 'react';
function TextInput() {
const inputRef = useRef(null);
function handleClick() {
inputRef.current.focus();
}
return (
<>
<input ref={inputRef} />
<button onClick={handleClick}>Focus input</button>
</>
);
}function Stopwatch() {
const [time, setTime] = useState(0);
const intervalRef = useRef(null);
function handleStart() {
intervalRef.current = setInterval(() => {
setTime(t => t + 1);
}, 10);
}
function handleStop() {
clearInterval(intervalRef.current);
}
return (
<div>
<p>Time: {(time / 100).toFixed(2)}s</p>
<button onClick={handleStart}>Start</button>
<button onClick={handleStop}>Stop</button>
</div>
);
}import { useRef, useState } from 'react';
function VideoPlayer({ src, isPlaying }) {
const ref = useRef(null);
useEffect(() => {
if (isPlaying) {
ref.current.play();
} else {
ref.current.pause();
}
}, [isPlaying]);
return <video ref={ref} src={src} loop playsInline />;
}
function App() {
const [isPlaying, setIsPlaying] = useState(false);
return (
<>
<button onClick={() => setIsPlaying(!isPlaying)}>
{isPlaying ? 'Pause' : 'Play'}
</button>
<VideoPlayer
isPlaying={isPlaying}
src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4"
/>
</>
);
}function LoginForm() {
const [formData, setFormData] = useState({
username: '',
password: '',
rememberMe: false
});
const [errors, setErrors] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
const handleChange = (field) => (e) => {
const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
setFormData(prev => ({ ...prev, [field]: value }));
};
const validate = () => {
const newErrors = {};
if (!formData.username) newErrors.username = 'Required';
if (!formData.password) newErrors.password = 'Required';
return newErrors;
};
const handleSubmit = async (e) => {
e.preventDefault();
const newErrors = validate();
if (Object.keys(newErrors).length > 0) {
setErrors(newErrors);
return;
}
setIsSubmitting(true);
try {
await login(formData);
} catch (error) {
setErrors({ submit: error.message });
} finally {
setIsSubmitting(false);
}
};
return (
<form onSubmit={handleSubmit}>
<input
value={formData.username}
onChange={handleChange('username')}
placeholder="Username"
/>
{errors.username && <span>{errors.username}</span>}
<input
type="password"
value={formData.password}
onChange={handleChange('password')}
placeholder="Password"
/>
{errors.password && <span>{errors.password}</span>}
<label>
<input
type="checkbox"
checked={formData.rememberMe}
onChange={handleChange('rememberMe')}
/>
Remember me
</label>
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? 'Logging in...' : 'Log in'}
</button>
{errors.submit && <div>{errors.submit}</div>}
</form>
);
}import { createContext, useContext, useState } from 'react';
const ThemeContext = createContext(null);
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within ThemeProvider');
}
return context;
}
// Usage
function App() {
return (
<ThemeProvider>
<Page />
</ThemeProvider>
);
}
function Page() {
const { theme, toggleTheme } = useTheme();
return (
<div className={`page-${theme}`}>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
}import { createContext, useContext, useReducer } from 'react';
// Context for tasks data
const TasksContext = createContext(null);
// Context for dispatch function
const TasksDispatchContext = createContext(null);
export function TasksProvider({ children }) {
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
return (
<TasksContext.Provider value={tasks}>
<TasksDispatchContext.Provider value={dispatch}>
{children}
</TasksDispatchContext.Provider>
</TasksContext.Provider>
);
}
export function useTasks() {
return useContext(TasksContext);
}
export function useTasksDispatch() {
return useContext(TasksDispatchContext);
}
function tasksReducer(tasks, action) {
switch (action.type) {
case 'added': {
return [...tasks, {
id: action.id,
text: action.text,
done: false
}];
}
case 'changed': {
return tasks.map(t => {
if (t.id === action.task.id) {
return action.task;
}
return t;
});
}
case 'deleted': {
return tasks.filter(t => t.id !== action.id);
}
default: {
throw Error('Unknown action: ' + action.type);
}
}
}
const initialTasks = [
{ id: 0, text: 'Philosopher's Path', done: true },
{ id: 1, text: 'Visit the temple', done: false },
{ id: 2, text: 'Drink matcha', done: false }
];
// Component using the pattern
function AddTask() {
const [text, setText] = useState('');
const dispatch = useTasksDispatch();
return (
<>
<input
placeholder="Add task"
value={text}
onChange={e => setText(e.target.value)}
/>
<button onClick={() => {
setText('');
dispatch({
type: 'added',
id: nextId++,
text: text,
});
}}>Add</button>
</>
);
}
function TaskList() {
const tasks = useTasks();
return (
<ul>
{tasks.map(task => (
<Task key={task.id} task={task} />
))}
</ul>
);
}
function Task({ task }) {
const [isEditing, setIsEditing] = useState(false);
const dispatch = useTasksDispatch();
let taskContent;
if (isEditing) {
taskContent = (
<>
<input
value={task.text}
onChange={e => {
dispatch({
type: 'changed',
task: {
...task,
text: e.target.value
}
});
}} />
<button onClick={() => setIsEditing(false)}>
Save
</button>
</>
);
} else {
taskContent = (
<>
{task.text}
<button onClick={() => setIsEditing(true)}>
Edit
</button>
</>
);
}
return (
<label>
<input
type="checkbox"
checked={task.done}
onChange={e => {
dispatch({
type: 'changed',
task: {
...task,
done: e.target.checked
}
});
}}
/>
{taskContent}
<button onClick={() => {
dispatch({
type: 'deleted',
id: task.id
});
}}>
Delete
</button>
</label>
);
}
let nextId = 3;import { useState, useEffect } from 'react';
function useWindowSize() {
const [size, setSize] = useState({
width: window.innerWidth,
height: window.innerHeight
});
useEffect(() => {
function handleResize() {
setSize({
width: window.innerWidth,
height: window.innerHeight
});
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return size;
}
// Usage
function Component() {
const { width, height } = useWindowSize();
return <div>{width} x {height}</div>;
}import { useState, useEffect } from 'react';
function useOnlineStatus() {
const [isOnline, setIsOnline] = useState(true);
useEffect(() => {
function handleOnline() {
setIsOnline(true);
}
function handleOffline() {
setIsOnline(false);
}
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
}, []);
return isOnline;
}
// Usage
function StatusBar() {
const isOnline = useOnlineStatus();
return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>;
}function useForm(initialValues, onSubmit) {
const [values, setValues] = useState(initialValues);
const [errors, setErrors] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
const handleChange = (name, value) => {
setValues(prev => ({ ...prev, [name]: value }));
// Clear error when user starts typing
if (errors[name]) {
setErrors(prev => ({ ...prev, [name]: null }));
}
};
const handleSubmit = async (e) => {
e.preventDefault();
setIsSubmitting(true);
try {
await onSubmit(values);
} catch (error) {
setErrors({ submit: error.message });
} finally {
setIsSubmitting(false);
}
};
const reset = () => {
setValues(initialValues);
setErrors({});
};
return {
values,
errors,
isSubmitting,
handleChange,
handleSubmit,
setErrors,
reset
};
}
// Usage
function ContactForm() {
const { values, errors, isSubmitting, handleChange, handleSubmit } = useForm(
{ name: '', email: '', message: '' },
async (data) => {
await fetch('/api/contact', {
method: 'POST',
body: JSON.stringify(data)
});
}
);
return (
<form onSubmit={handleSubmit}>
<input
value={values.name}
onChange={(e) => handleChange('name', e.target.value)}
/>
{errors.name && <span>{errors.name}</span>}
<input
value={values.email}
onChange={(e) => handleChange('email', e.target.value)}
/>
{errors.email && <span>{errors.email}</span>}
<textarea
value={values.message}
onChange={(e) => handleChange('message', e.target.value)}
/>
{errors.message && <span>{errors.message}</span>}
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? 'Sending...' : 'Send'}
</button>
</form>
);
}function useFetch(url, options = {}) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let cancelled = false;
async function fetchData() {
try {
setLoading(true);
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
if (!cancelled) {
setData(result);
setError(null);
}
} catch (err) {
if (!cancelled) {
setError(err.message);
setData(null);
}
} finally {
if (!cancelled) {
setLoading(false);
}
}
}
fetchData();
return () => {
cancelled = true;
};
}, [url, JSON.stringify(options)]);
return { data, loading, error };
}
// Usage
function UserProfile({ userId }) {
const { data, loading, error } = useFetch(`/api/users/${userId}`);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return <div>{data.name}</div>;
}function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(error);
return initialValue;
}
});
const setValue = (value) => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue];
}
// Usage
function Settings() {
const [theme, setTheme] = useLocalStorage('theme', 'light');
const [fontSize, setFontSize] = useLocalStorage('fontSize', 16);
return (
<div>
<select value={theme} onChange={(e) => setTheme(e.target.value)}>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
<input
type="number"
value={fontSize}
onChange={(e) => setFontSize(parseInt(e.target.value))}
/>
</div>
);
}import { memo } from 'react';
const ExpensiveComponent = memo(function ExpensiveComponent({ data, onAction }) {
console.log('Rendering expensive component');
return (
<div>
{data.map(item => (
<div key={item.id}>{item.name}</div>
))}
<button onClick={onAction}>Action</button>
</div>
);
});
// With custom comparison
const CustomMemoComponent = memo(
function Component({ user }) {
return <div>{user.name}</div>;
},
(prevProps, nextProps) => {
// Return true if props are equal (skip re-render)
return prevProps.user.id === nextProps.user.id;
}
);import { lazy, Suspense } from 'react';
const HeavyComponent = lazy(() => import('./HeavyComponent'));
const AdminPanel = lazy(() => import('./AdminPanel'));
function App() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</Suspense>
</div>
);
}
// Lazy loading with routes
function Dashboard() {
const [showAdmin, setShowAdmin] = useState(false);
return (
<div>
<button onClick={() => setShowAdmin(true)}>
Show Admin Panel
</button>
{showAdmin && (
<Suspense fallback={<Spinner />}>
<AdminPanel />
</Suspense>
)}
</div>
);
}import { lazy, Suspense } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Dashboard = lazy(() => import('./pages/Dashboard'));
function App() {
return (
<BrowserRouter>
<Suspense fallback={<div>Loading page...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}function VirtualList({ items, height, itemHeight }) {
const [scrollTop, setScrollTop] = useState(0);
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = Math.min(
startIndex + Math.ceil(height / itemHeight),
items.length
);
const visibleItems = items.slice(startIndex, endIndex);
const offsetY = startIndex * itemHeight;
const totalHeight = items.length * itemHeight;
return (
<div
style={{ height, overflow: 'auto' }}
onScroll={(e) => setScrollTop(e.target.scrollTop)}
>
<div style={{ height: totalHeight, position: 'relative' }}>
<div style={{ transform: `translateY(${offsetY}px)` }}>
{visibleItems.map((item, index) => (
<div
key={startIndex + index}
style={{ height: itemHeight }}
>
{item}
</div>
))}
</div>
</div>
</div>
);
}// ❌ Bad - missing dependencies
useEffect(() => {
fetchData(userId);
}, []);
// ✅ Good - all dependencies included
useEffect(() => {
fetchData(userId);
}, [userId]);useEffect(() => {
const subscription = api.subscribe(id);
return () => {
subscription.unsubscribe();
};
}, [id]);// ✅ Good - separate contexts
const TasksContext = createContext(null);
const TasksDispatchContext = createContext(null);
// Components that only dispatch won't re-render when tasks change
function AddTask() {
const dispatch = useTasksDispatch(); // No re-render when tasks change
// ...
}// ❌ Bad - new object on every render
<Component style={{ margin: 10 }} />
// ✅ Good - memoized object
const style = useMemo(() => ({ margin: 10 }), []);
<Component style={style} />// ❌ Bad - may use stale state
setCount(count + 1);
// ✅ Good - uses current state
setCount(prevCount => prevCount + 1);// ✅ Good - complex logic in reducer
function cartReducer(state, action) {
switch (action.type) {
case 'add_item':
// Complex logic here
return newState;
case 'remove_item':
// Complex logic here
return newState;
default:
return state;
}
}// ❌ Bad - using index as key
{items.map((item, index) => <div key={index}>{item}</div>)}
// ✅ Good - using unique ID
{items.map(item => <div key={item.id}>{item.text}</div>)}function Form() {
const [value, setValue] = useState('');
return (
<input
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
}class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
console.error('Error caught:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
// Usage
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>import PropTypes from 'prop-types';
function User({ name, age, email }) {
return <div>{name} ({age})</div>;
}
User.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number.isRequired,
email: PropTypes.string
};
User.defaultProps = {
email: 'no-email@example.com'
};function MultiStepForm() {
const [step, setStep] = useState(1);
const [formData, setFormData] = useState({
personalInfo: {},
address: {},
preferences: {}
});
const updateFormData = (section, data) => {
setFormData(prev => ({
...prev,
[section]: { ...prev[section], ...data }
}));
};
const nextStep = () => setStep(s => s + 1);
const prevStep = () => setStep(s => s - 1);
return (
<div>
{step === 1 && (
<PersonalInfoStep
data={formData.personalInfo}
onNext={(data) => {
updateFormData('personalInfo', data);
nextStep();
}}
/>
)}
{step === 2 && (
<AddressStep
data={formData.address}
onNext={(data) => {
updateFormData('address', data);
nextStep();
}}
onPrev={prevStep}
/>
)}
{step === 3 && (
<PreferencesStep
data={formData.preferences}
onSubmit={(data) => {
updateFormData('preferences', data);
submitForm({ ...formData, preferences: data });
}}
onPrev={prevStep}
/>
)}
</div>
);
}function InfiniteScroll() {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(false);
const [hasMore, setHasMore] = useState(true);
const loadMore = useCallback(async () => {
if (loading || !hasMore) return;
setLoading(true);
try {
const newItems = await fetchItems(page);
setItems(prev => [...prev, ...newItems]);
setHasMore(newItems.length > 0);
setPage(p => p + 1);
} finally {
setLoading(false);
}
}, [page, loading, hasMore]);
useEffect(() => {
const handleScroll = () => {
if (
window.innerHeight + window.scrollY >=
document.documentElement.scrollHeight - 500
) {
loadMore();
}
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, [loadMore]);
return (
<div>
{items.map(item => <Item key={item.id} data={item} />)}
{loading && <div>Loading...</div>}
{!hasMore && <div>No more items</div>}
</div>
);
}function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
}
function SearchComponent() {
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearchTerm = useDebounce(searchTerm, 500);
const [results, setResults] = useState([]);
useEffect(() => {
if (debouncedSearchTerm) {
searchAPI(debouncedSearchTerm).then(setResults);
} else {
setResults([]);
}
}, [debouncedSearchTerm]);
return (
<div>
<input
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Search..."
/>
<ul>
{results.map(result => (
<li key={result.id}>{result.title}</li>
))}
</ul>
</div>
);
}import { createPortal } from 'react-dom';
function Modal({ isOpen, onClose, children }) {
if (!isOpen) return null;
return createPortal(
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
<button className="close-button" onClick={onClose}>×</button>
{children}
</div>
</div>,
document.body
);
}
// Usage
function App() {
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<div>
<button onClick={() => setIsModalOpen(true)}>Open Modal</button>
<Modal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)}>
<h2>Modal Content</h2>
<p>This is a modal dialog</p>
</Modal>
</div>
);
}function DragDropList() {
const [items, setItems] = useState([
{ id: 1, text: 'Item 1' },
{ id: 2, text: 'Item 2' },
{ id: 3, text: 'Item 3' }
]);
const [draggedItem, setDraggedItem] = useState(null);
const handleDragStart = (item) => {
setDraggedItem(item);
};
const handleDragOver = (e) => {
e.preventDefault();
};
const handleDrop = (targetItem) => {
if (!draggedItem || draggedItem.id === targetItem.id) return;
const draggedIndex = items.findIndex(i => i.id === draggedItem.id);
const targetIndex = items.findIndex(i => i.id === targetItem.id);
const newItems = [...items];
newItems.splice(draggedIndex, 1);
newItems.splice(targetIndex, 0, draggedItem);
setItems(newItems);
setDraggedItem(null);
};
return (
<ul>
{items.map(item => (
<li
key={item.id}
draggable
onDragStart={() => handleDragStart(item)}
onDragOver={handleDragOver}
onDrop={() => handleDrop(item)}
>
{item.text}
</li>
))}
</ul>
);
}