Comprehensive guide covering hooks, performance optimization, state management, and advanced React concepts
useCallback is a hook that returns a memoized version of a callback function. It prevents the function from being recreated on every render, which is useful when passing callbacks to child components to avoid unnecessary re-renders.
Example:
import { useCallback, useState } from 'react'; function Parent() { const [count, setCount] = useState(0); const handleClick = useCallback(() => { console.log('Button clicked!'); }, []); // Empty dependency array means function is memoized return <Child onClick={handleClick} />; }
useMemo is a hook that memoizes the result of a computation, so it's only recalculated when dependencies change. Use it to optimize performance for expensive calculations.
Example:
import { useMemo, useState } from 'react'; function ExpensiveComponent({ numbers }) { const sum = useMemo(() => { return numbers.reduce((a, b) => a + b, 0); }, [numbers]); return <div>Sum: {sum}</div>; }
Side effects (like data fetching, timers, or DOM updates) are handled using the useEffect hook in functional components or lifecycle methods (componentDidMount
, componentDidUpdate
, componentWillUnmount
) in class components.
Example with useEffect:
import { useEffect, useState } from 'react'; function DataFetcher() { const [data, setData] = useState(null); useEffect(() => { fetch('https://api.example.com/data') .then(res => res.json()) .then(setData); return () => console.log('Cleanup'); // Cleanup on unmount }, []); return <div>{data ? data.name : 'Loading...'}</div>; }
A Pure Component is a class component that automatically implements shouldComponentUpdate
with a shallow comparison of props and state to prevent unnecessary re-renders. Functional components can achieve this with React.memo
.
Example:
class PureComp extends React.PureComponent { render() { return <div>{this.props.value}</div>; } }
Example:
import { useLayoutEffect } from 'react'; function LayoutEffectExample() { useLayoutEffect(() => { console.log('Runs before painting'); }, []); return <div>Hello</div>; }
To prevent unnecessary re-renders:
React.memo
for functional components to skip renders if props haven't changed.shouldComponentUpdate
or extend PureComponent
in class components.Example with React.memo:
const MyComponent = React.memo(({ value }) => { return <div>{value}</div>; });
useRef creates a mutable object that persists across renders. It's commonly used to:
Example:
import { useRef } from 'react'; function InputFocus() { const inputRef = useRef(null); const focusInput = () => inputRef.current.focus(); return ( <div> <input ref={inputRef} /> <button onClick={focusInput}>Focus</button> </div> ); }
Authentication can be handled by:
Example:
import { useContext } from 'react'; import { AuthContext } from './AuthContext'; function ProtectedRoute({ children }) { const { isAuthenticated } = useContext(AuthContext); return isAuthenticated ? children : <Redirect to="/login" />; }
React.Fragment lets you group multiple elements without adding extra DOM nodes (like a <div>
). It's useful for cleaner HTML output.
Example:
function List() { return ( <React.Fragment> <li>Item 1</li> <li>Item 2</li> </React.Fragment> ); }
Lazy loading delays loading of components until they're needed, improving app performance. Use React.lazy and Suspense.
Example:
import { lazy, Suspense } from 'react'; const LazyComponent = lazy(() => import('./LazyComponent')); function App() { return ( <Suspense fallback={<div>Loading...</div>}> <LazyComponent /> </Suspense> ); }
Example:
function Example() { const [count, setCount] = useState(0); // Triggers re-render const refCount = useRef(0); // No re-render return ( <div> <button onClick={() => setCount(count + 1)}>State: {count}</button> <button onClick={() => (refCount.current += 1)}>Ref: {refCount.current}</button> </div> ); }
Use try-catch in async functions inside useEffect
or other hooks, and maintain an error state to display error messages.
Example:
import { useState, useEffect } from 'react'; function DataFetcher() { const [data, setData] = useState(null); const [error, setError] = useState(null); useEffect(() => { async function fetchData() { try { const res = await fetch('https://api.example.com/data'); const result = await res.json(); setData(result); } catch (err) { setError('Failed to fetch data'); } } fetchData(); }, []); return <div>{error ? error : data ? data.name : 'Loading...'}</div>; }
The key prop uniquely identifies elements in a list, helping React efficiently update the DOM. Without a key
, React may re-render the entire list, causing performance issues or incorrect UI updates.
Example:
const items = ['Apple', 'Banana']; function List() { return ( <ul> {items.map(item => ( <li key={item}>{item}</li> // Use unique key ))} </ul> ); }
Global state can be managed using:
Example with Context:
const GlobalContext = React.createContext(); function App() { const [state, setState] = useState({ theme: 'light' }); return ( <GlobalContext.Provider value={{ state, setState }}> <Child /> </GlobalContext.Provider> ); }
Example:
const MemoizedComponent = React.memo(({ value }) => <div>{value}</div>); const expensiveValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
React components can be tested using libraries like:
Example:
import { render, screen } from '@testing-library/react'; test('renders button', () => { render(<Button label="Click me" />); expect(screen.getByText('Click me')).toBeInTheDocument(); });
React.StrictMode is a tool for highlighting potential problems in a React app during development. It:
Example:
function App() { return ( <React.StrictMode> <MyComponent /> </React.StrictMode> ); }
Use React Router to manage routing in an SPA. It allows navigation without full page reloads. Key components:
Example:
import { BrowserRouter, Route, Switch } from 'react-router-dom'; function App() { return ( <BrowserRouter> <Switch> <Route path="/home" component={Home} /> <Route path="/about" component={About} /> </Switch> </BrowserRouter> ); }
Custom hooks are reusable functions that encapsulate logic using React hooks. They start with "use" and can call other hooks.
Example:
import { useState, useEffect } from 'react'; function useFetch(url) { const [data, setData] = useState(null); useEffect(() => { fetch(url) .then(res => res.json()) .then(setData); }, [url]); return data; } function Component() { const data = useFetch('https://api.example.com/data'); return <div>{data ? data.name : 'Loading...'}</div>; }
To make a React app SEO-friendly:
react-helmet
.Example with react-helmet:
import { Helmet } from 'react-helmet'; function Page() { return ( <div> <Helmet> <title>My Page Title</title> <meta name="description" content="This is my page" /> </Helmet> <h1>Hello</h1> </div> ); }
useMemo
vs. useCallback
.