![]()
A common React mistake is not providing proper default values for state in functional components, which can lead to:
undefinedstate errors- Broken component rendering
- Unexpected runtime behavior
- Difficult-to-debug issues
The Problem
// ❌ Problematic - no default value for potentially undefined prop
function UserProfile({ user }) {
const [name, setName] = useState(user.name); // Error if user is undefined
return <div>{name}</div>;
}
// ❌ Another bad pattern
function Counter() {
const [count] = useState(); // count will be undefined
return <div>{count + 1}</div>; // NaN error
}
Correct Solutions
1. Basic Default Values
// ✅ Provide sensible defaults
function UserProfile({ user }) {
const [name, setName] = useState(user?.name ?? 'Guest');
return <div>{name}</div>;
}
2. Default Props Pattern
// ✅ Using defaultProps (for class-like consistency)
function UserProfile({ user }) {
const [name, setName] = useState(user.name);
return <div>{name}</div>;
}
UserProfile.defaultProps = {
user: { name: 'Guest' }
};
3. Fallback Objects
// ✅ Safely destructure with fallback
function UserProfile({ user = {} }) {
const [name, setName] = useState(user.name || 'Guest');
return <div>{name}</div>;
}
4. TypeScript Solution
// ✅ With TypeScript interfaces
interface User {
name: string;
age?: number;
}
function UserProfile({ user = { name: 'Guest' } }: { user?: User }) {
const [name, setName] = useState(user.name);
return <div>{name}</div>;
}
Common Scenarios and Fixes
1. Array State
// ❌ Bad
const [items, setItems] = useState(); // items is undefined
// ✅ Good
const [items, setItems] = useState([]); // Default empty array
2. Object State
// ❌ Bad
const [config, setConfig] = useState();
// ✅ Good
const [config, setConfig] = useState({
theme: 'light',
notifications: true
});
3. Boolean State
// ❌ Ambiguous
const [isOpen, setIsOpen] = useState();
// ✅ Clear default
const [isOpen, setIsOpen] = useState(false);
Best Practices
- Always initialize state – Never leave useState() empty
- Match the expected type – Keep consistent data structures
- Consider null state – Sometimes better than empty defaults
- Document expected shape – With PropTypes or TypeScript
- Use destructuring defaults – For props and state
Advanced Patterns
1. Lazy Initial State
// ✅ For expensive initial state
const [data, setData] = useState(() => {
const initialValue = calculateExpensiveValue(props.someValue);
return initialValue;
});
2. Custom Hook with Defaults
function useSafeState(initialValue) {
return useState(initialValue ?? getDefaultValue());
}
// Usage
const [count, setCount] = useSafeState(); // Uses default
3. Reducer Default State
const initialState = { count: 0 };
function reducer(state = initialState, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
default:
return state;
}
}
const [state, dispatch] = useReducer(reducer, initialState);
- What happens if the prop is undefined?
- What’s a sensible default for this state?
- How will this component behave on first render?
