React is a powerful library for building user interfaces. Following best practices ensures maintainable, performant, and scalable code. Here's a comprehensive guide based on React's documentation and community insights.
Core Best Practices from React Docs
1. Treat Props as Readonly
Props must not be modified. Treat them as immutable inputs.
function Welcome({ name }) {
return <h1>Hello, {name}!</h1>; // Avoid modifying props directly
}
2. State Management
- Always use
setState
or equivalent to modify state.
setState(prev => ({ count: prev.count + 1 }));
- Clean up resources like timers in lifecycle methods or
useEffect
:
useEffect(() => {
const timer = setInterval(() => console.log('Tick'), 1000);
return () => clearInterval(timer); // Cleanup
}, []);
3. Bind Functions Efficiently
Use arrow functions or bind functions in the constructor.
class MyComponent extends React.Component {
constructor() {
super();
this.handleClick = this.handleClick.bind(this);
}
}
4. Use Stable Keys for Lists
Provide unique, stable keys when rendering lists.
const items = ['Apple', 'Banana'];
items.map(item => <li key={item}>{item}</li>);
5. Lift State Up
Share state by lifting it to the nearest common ancestor.
function Parent() {
const [value, setValue] = useState('');
return (
<>
<ChildInput value={value} onChange={setValue} />
<ChildDisplay value={value} />
</>
);
}
6. Avoid Context Misuse
Reserve context for specific cases like theming or authentication.
const ThemeContext = React.createContext('light');
7. Leverage Pure Components
Optimize performance using React.PureComponent
or React.memo
.
const MemoizedComponent = React.memo(({ value }) => <div>{value}</div>);
Presentation vs. Container Components
- Presentational Components handle UI rendering.
- Container Components manage state and logic.
Example:
function Button({ label, onClick }) {
return <button onClick={onClick}>{label}</button>; // Presentational
}
function Counter() {
const [count, setCount] = useState(0);
return <Button label={`Count: ${count}`} onClick={() => setCount(count + 1)} />; // Container
}
Performance Optimizations
1. Avoid Mutating State
Use the spread operator or immutable libraries.
const newState = { ...oldState, key: 'newValue' };
2. Avoid Index as Keys
Using indices can lead to issues during reordering.
const list = ['A', 'B'];
list.map(item => <div key={item}>{item}</div>);
3. Memoize Expensive Operations
Use useMemo
and useCallback
to optimize calculations.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Additional Best Practices
Prefer Functional Components
Use functional components with hooks over class-based ones.
function MyComponent() {
const [count, setCount] = useState(0);
return <div>{count}</div>;
}
Define defaultProps
Provide default values for props.
Button.defaultProps = {
label: 'Click me',
};
Avoid Overusing State
Keep state minimal and centralized.
const initialState = { user: null, theme: 'dark' };
Normalize Data Structures
Use normalized formats for entities.
const state = {
users: { 1: { id: 1, name: 'John' } },
posts: { 1: { id: 1, title: 'Hello', authorId: 1 } },
};
Anti-Patterns to Avoid
1. Nested State
Deeply nested states make updates cumbersome.
// Avoid this
const state = { user: { preferences: { theme: 'dark' } } };
2. Logic in Render Methods
Cache derived data instead of recalculating during renders.
const derived = useMemo(() => items.filter(item => item.active), [items]);
3. Inline Functions in JSX
Declare functions outside render for performance.
const handleClick = () => setState(state + 1);
Wrapping Up
By adhering to these best practices, you’ll write cleaner, more efficient React code.
Consistency leads to fewer bugs, better performance, and improved collaboration.
Apply these tips, and you’ll level up your React projects!
Top comments (1)
Class components are deprecated for a while now. So, binding functions is not something you have to do anymore.
Since React 19, defaultProps are also deprecated, use es6 syntax for assigning default values for your component props: