React Curriculum

Derived State vs Redundant State Patterns

Medium100% Free~20 mins#react#derived-state#redundant-state#state-structure#anti-patterns
Interview Answer (30-Second Summary)

If a value can be computed from existing props or state, never mirror it in state. Storing derived values in state creates duplicate sources of truth that easily become desynchronized and trigger unnecessary extra re-renders.

Key Learning Objectives
✓

Recognize the redundant state anti-pattern and why copying props to state causes desync bugs.

✓

Compute derived values during render instead of synchronizing them in useEffect.

✓

Use useMemo responsibly only when derived calculations are computationally expensive.

✓

Structure state around minimal, normalized data representations.

The Interview Problem & Context

Refactor the following component to eliminate redundant state synchronization. What are the key principles for determining whether a value should live in state?

1// ❌ ANTI-PATTERN: Copying props/state into redundant state via useEffect
2function BadUserList({ users, filterText }: { users: User[]; filterText: string }) {
3 const [filteredUsers, setFilteredUsers] = useState<User[]>([]);
4
5 // Buggy & slow: triggers an extra, redundant re-render every time filterText changes!
6 useEffect(() => {
7 setFilteredUsers(users.filter(u => u.name.toLowerCase().includes(filterText.toLowerCase())));
8 }, [users, filterText]);
9
10 return <ul>{filteredUsers.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
11}
12
13// ✅ BEST PRACTICE: Derived state calculated directly during render
14function GoodUserList({ users, filterText }: { users: User[]; filterText: string }) {
15 // Pure calculation: runs during render with zero extra re-renders or useEffect latency
16 const filteredUsers = users.filter(u =>
17 u.name.toLowerCase().includes(filterText.toLowerCase())
18 );
19
20 return <ul>{filteredUsers.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
21}
Deep Architectural Explanation

The Golden Rule of React State Structure

Don't put in state what you can compute from props or existing state.

Why Redundant State Causes Bugs

When you duplicate data into state via useEffect:

  1. Double Rendering: The component renders with old state, then useEffect runs, updates state, and forces a second re-render.
  2. Desynchronization Glitches: Between render 1 and render 2, the UI displays outdated or mismatched data.
  3. Boilerplate & Complexity: You now have to maintain dependency arrays and ensure all update pathways update both variables.

When to Use useMemo for Derived Values

Calculate derived values directly in the component body:

tsx
const filteredList = items.filter(item => item.active);

Only wrap in useMemo if:

  1. The calculation involves thousands of items or expensive algorithms (e.g. > 1ms execution time).
  2. The derived object/array reference is passed to a memoized child component (React.memo) that requires referential stability.
Common Interview Traps & Pitfalls
✕

Using useEffect to sync filtered lists, search results, or selected item IDs into state.

✕

Copying props into initial state: const [name, setName] = useState(props.initialName) and expecting it to update when props change.

✕

Wrapping every simple derived expression in useMemo, adding more overhead than the calculation itself.

Senior Interviewer Follow-Up Probes
?

How do you reset component state when a prop changes without using useEffect?

?

What is the difference between initial state and synced state in React?

?

How does the React team's "You Might Not Need an Effect" documentation advise handling derived state?

Frequently Asked Interview Questions
What is derived state in React?

Derived state is any value that can be computed on-the-fly from existing props or state during the component render execution, without needing its own useState container.

It causes a double render pass (first with outdated state, then with updated state), introduces brief visual UI flickers, and creates synchronization bugs.

Only when the calculation is computationally expensive (sorting or filtering large datasets) or when the resulting array/object is passed as a prop to a memoized child component.

By passing a unique key prop to the component: <UserProfile key={userId} userId={userId} />. React automatically unmounts and remounts a fresh instance with clean state.

It means each piece of data is stored in exactly one place. All other views, counts, and filters are calculated from that single source, eliminating data discrepancies.