When working with React code, apply these principles in order of importance:
1. Think in React
Follow the 5-step process for building React UIs:
- Break UI into component hierarchy β One component = one responsibility
- Build static version first β Use props only, no state yet
- Find minimal state β Ask: Does it change? Is it passed via props? Can it be computed?
- Identify where state lives β Find closest common parent of components that need it
- Add inverse data flow β Pass callbacks down to update parent state
2. Keep Components Pure
Components must be pure functions during rendering:
```jsx
// β Mutates external variable
let guest = 0;
function Cup() {
guest = guest + 1;
return Guest #{guest}
;
}
// β
Uses props
function Cup({ guest }) {
return Guest #{guest}
;
}
```
Rules:
- Never mutate props, state, or context during render
- Same inputs = same output
- Side effects belong in event handlers or useEffect
3. State Management
Minimize state:
```jsx
// β Redundant state
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [fullName, setFullName] = useState(''); // redundant!
// β
Compute during render
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const fullName = firstName + ' ' + lastName;
```
Lift state up when siblings need the same data β move to closest common parent.
Use key to reset state:
```jsx
// Forces fresh component instance when recipient changes
```
4. Hooks Rules
Only call hooks at the top level:
- Never in loops, conditions, or nested functions
- Never after early returns
- React relies on consistent call order
Only call hooks from React functions:
- Function components or custom hooks only
5. Effects β Use Sparingly
Effects are for synchronizing with external systems, not for state logic.
You DON'T need useEffect for:
| Scenario | Instead of Effect | Do This |
|----------|-------------------|---------|
| Transform data for render | useEffect + setState | Calculate during render |
| Cache expensive calculations | useEffect + setState | useMemo |
| Reset state on prop change | useEffect + setState | Use key prop |
| Handle user events | useEffect watching state | Event handler directly |
| Notify parent of changes | useEffect calling callback | Call in event handler |
When you DO need useEffect:
- Fetching data (with cleanup for race conditions)
- Subscribing to events (with cleanup to unsubscribe)
- Controlling non-React widgets
- Connecting to external systems
Always add cleanup:
```jsx
useEffect(() => {
const connection = createConnection();
connection.connect();
return () => connection.disconnect(); // cleanup
}, []);
```
6. Performance
Before reaching for memo:
- Move state down β Isolate state to components that use it
- Lift content up β Pass expensive subtrees as
children
Virtualize large lists (50+ items):
```jsx
import { FixedSizeList } from 'react-window';
{({ index, style }) => {items[index]}
}
```
Code split routes:
```jsx
const Dashboard = lazy(() => import('./Dashboard'));
}>
```
7. Component Design Principles
From "Writing Resilient Components":
- Don't stop the data flow β Read props directly, don't copy to state
- Always be ready to render β Don't assume render timing or frequency
- No component is a singleton β Design as if rendered multiple times
- Keep local state isolated β Only local if it wouldn't sync across copies
8. Context β Use Judiciously
Good for: theming, current user, routing, widely-needed state.
Try these first:
- Pass props explicitly β clearer data flow
- Extract components and use
children β avoids prop drilling
```jsx
// β Prop drilling
// β
Composition
```