React is a JavaScript library for building user interfaces, particularly single-page applications. It is maintained by Meta and a community of individual developers and companies.
Use this file to discover all available pages before exploring further.
React Anti-Patterns Overview
React, despite its popularity and robust ecosystem, has several common anti-patterns that can lead to performance issues, maintenance problems, and bugs. Here are the most important anti-patterns to avoid when writing React code.
Prop drilling makes components tightly coupled and harder to maintain. Use Context API or state management libraries like Redux for sharing state across components.
Inline function definitions create new function instances on every render, which can lead to unnecessary re-renders of child components. Use useCallback to memoize functions.
Not Using React Keys Properly
// Anti-pattern: Using index as keyfunction TodoList({ todos }) { return ( <ul> {todos.map((todo, index) => ( <li key={index}>{todo.text}</li> ))} </ul> );}// Better approach: Use unique IDsfunction TodoList({ todos }) { return ( <ul> {todos.map(todo => ( <li key={todo.id}>{todo.text}</li> ))} </ul> );}
Using array indices as keys can lead to performance issues and bugs when items are added, removed, or reordered. Use stable, unique identifiers for keys.
Components re-render even when their props haven’t changed, causing unnecessary renders. Use React.memo to skip re-rendering when props are unchanged.
Improper useEffect Dependencies
// Anti-pattern: Missing or incorrect dependenciesfunction UserProfile({ userId }) { const [user, setUser] = useState(null); // Missing dependency useEffect(() => { fetchUser(userId).then(data => setUser(data)); }, []); // userId should be in the dependency array return user ? <div>{user.name}</div> : <div>Loading...</div>;}// Better approach: Proper dependenciesfunction UserProfile({ userId }) { const [user, setUser] = useState(null); useEffect(() => { fetchUser(userId).then(data => setUser(data)); }, [userId]); // Correctly includes userId return user ? <div>{user.name}</div> : <div>Loading...</div>;}
Missing or incorrect dependencies in useEffect can lead to stale closures and bugs. Always include all values from the component scope that the effect uses.
Not Using Fragment for Multiple Elements
// Anti-pattern: Unnecessary div wrapperfunction UserInfo({ user }) { return ( <div> <h2>{user.name}</h2> <p>{user.email}</p> </div> );}// Better approach: Use Fragmentfunction UserInfo({ user }) { return ( <> <h2>{user.name}</h2> <p>{user.email}</p> </> );}
Unnecessary wrapper divs add to the DOM depth and can break layouts. Use React Fragments (<>...</> or <React.Fragment>) to group elements without adding extra nodes to the DOM.
Without error boundaries, a runtime error in a component can break the entire application. Use error boundaries to gracefully handle errors and display fallback UIs.
Uncontrolled components make it harder to validate and manipulate form data. Use controlled components for better control over form inputs and validation.
Not Using React DevTools
// Anti-pattern: Debugging with console.logfunction ComplexComponent({ data }) { console.log('Component rendered', data); // Component logic return <div>{/* JSX */}</div>;}// Better approach: Use React DevTools and named componentsfunction ComplexComponent({ data }) { // No console.log, use React DevTools instead return <div>{/* JSX */}</div>;}
Using console.log for debugging is inefficient. Use React DevTools for inspecting component hierarchies, props, state, and performance.