Suggest an editImprove this articleRefine the answer for “What is React.PureComponent”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**React.PureComponent** is a class component base that skips re-renders by running a built-in shallow comparison on props and state before each render. ```jsx class MyComponent extends React.PureComponent { render() { return <div>{this.props.value}</div>; } } // Won't re-render if props.value stays the same ``` **Key:** shallow comparison only - nested object mutations are invisible to it. Functional equivalent: `React.memo`.Shown above the full answer for quick recall.Answer (EN)Image**React.PureComponent** is a base class for React class components that skips re-renders by running a shallow equality check on props and state before each render. ## Theory ### TL;DR - Think of it like a label check: PureComponent looks at the tag on the box (the reference), not what's inside. - Main difference from `React.Component`: PureComponent has a built-in `shouldComponentUpdate` that compares props and state shallowly. - Flat props (numbers, strings, stable object references) work great. Nested mutations will be missed. - For functional components, use `React.memo` instead. ### Quick example ```tsx import React, { PureComponent, Component } from 'react'; class PureChild extends PureComponent<{ count: number }> { render() { console.log('PureChild renders'); return <div>Count: {this.props.count}</div>; } } class RegularChild extends Component<{ count: number }> { render() { console.log('RegularChild renders'); return <div>Count: {this.props.count}</div>; } } class Parent extends Component { state = { count: 0 }; render() { return ( <> <PureChild count={this.state.count} /> <RegularChild count={this.state.count} /> {/* count stays 0, but parent still calls setState */} <button onClick={() => this.setState({ count: this.state.count })}> No change </button> </> ); } } // Click the button: only "RegularChild renders" logs. PureChild skips. ``` Both receive the same `count` after the click. `RegularChild` renders anyway. `PureChild` checks, finds nothing changed, and bails out. ### Key difference `React.Component` re-renders every time the parent updates or `setState` is called, regardless of whether data actually changed. `React.PureComponent` overrides `shouldComponentUpdate` with a shallow comparison: it iterates over each prop and state key and checks values with `Object.is`. If nothing changed, React skips the render and the entire subtree diff. The shallow check adds a small CPU cost per render, but that is almost always cheaper than diffing a whole subtree. ### When to use - Props are primitives (numbers, strings, booleans): PureComponent gives free optimization with no extra code. - Object props are stable references (memoized with `useMemo` or created once outside render): the shallow check passes correctly. - Lists with 50-100+ items where the parent re-renders often but individual items rarely change: PureComponent can cut redundant renders significantly. - Nested objects mutate in place: skip PureComponent. It will miss the change and show stale UI. - Functional component: use `React.memo` - same idea, works with hooks. ### Comparison table | Feature | React.Component | React.PureComponent | |---|---|---| | Re-render trigger | Any parent update or setState | Parent update + actual prop/state change | | shouldComponentUpdate | Not set by default | Built-in shallow comparison | | Handles in-place mutations | Yes (always re-renders) | No (misses deep changes) | | Works well with | Any props shape | Flat or stable-reference props | | Functional equivalent | N/A | React.memo | ### How it works internally `PureComponent` sets a flag (`isPureReactComponent = true`) that React's reconciler reads. Before calling `render`, React runs the built-in `shouldComponentUpdate`, which uses `Object.is` to compare each key in props and state. If all comparisons match, the component and its entire subtree skip reconciliation. In React 16+ with fiber, this bail-out is efficient: React skips the diff, skips `render`, and moves on to the next work unit. ### Common mistakes **Mutating objects or arrays in place:** ```tsx // Wrong: same array reference, PureComponent skips the re-render this.props.items[0].done = true; this.forceUpdate(); // a hack, and still won't help PureComponent children // Right: create a new reference this.setState({ items: this.state.items.map((item, i) => i === 0 ? { ...item, done: true } : item ) }); ``` PureComponent sees the same array reference and skips. The UI stays stale. This is the most common production bug with PureComponent. **Passing a new object literal on every render:** ```tsx // Wrong: new object each render defeats the shallow check entirely <PureChild config={{ theme: 'dark' }} /> // Right: stable reference const config = useMemo(() => ({ theme: 'dark' }), []); <PureChild config={config} /> ``` You get the overhead of the shallow check with zero benefit. PureComponent re-renders on every cycle. **Assuming it handles nested data changes:** If you spread the top-level object but mutate a nested property in place, behavior becomes unpredictable depending on whether the top-level reference changes. Always copy nested objects too: `{ ...user, details: { ...user.details, age: 31 } }`. Anything less is a bug waiting to surface. ### Real-world usage - Large data tables and lists: wrap each row in PureComponent so only changed rows re-render when the parent updates. - Material-UI TableRow and Ant Design table rows use PureComponent internally for exactly this reason. - Redux-connected lists: combine PureComponent with reselect selectors so components re-render only when their slice of state changes. - React DevTools Profiler: add PureComponent to a bottleneck component and check "why did this render?" to confirm skips are happening. I find PureComponent most useful in list scenarios. Add 100 items, toggle one, and you can watch 99 components skip their render in the Profiler without any guesswork. ### Follow-up questions **Q:** What is the difference between shallow and deep equality? **A:** Shallow checks each key's value with `Object.is`, one level deep. Deep equality recurses into nested values. Deep is expensive and rarely needed if you keep state immutable. **Q:** Can you override `shouldComponentUpdate` on a PureComponent? **A:** Yes. Your override replaces the built-in shallow check entirely. Do this only if you need custom comparison logic, like ignoring certain props. **Q:** What is the functional component equivalent of PureComponent? **A:** `React.memo`. It wraps a function component and does the same shallow prop comparison. Pass a custom comparator as the second argument if you need more control. **Q:** Does PureComponent affect error boundaries? **A:** No. If `render` throws, the error still bubbles up to the nearest error boundary regardless of whether the shallow check ran. **Q:** In React 18 concurrent mode, does PureComponent help with async rendering? **A:** PureComponent's check is synchronous. For async rendering benefits, combine `React.memo` with `useDeferredValue`. PureComponent alone does not interact with concurrent features. ## Examples ### List row optimization You have 100+ todo items. The parent re-renders on any state change, but each row should only re-render if its own data changed. ```tsx interface Todo { id: number; text: string; done: boolean; } class TodoItem extends React.PureComponent<{ todo: Todo }> { render() { const { todo } = this.props; console.log(`Rendering todo #${todo.id}`); return ( <li style={{ textDecoration: todo.done ? 'line-through' : 'none' }}> {todo.text} </li> ); } } // Parent re-renders the list on every change. // Toggle todo #3 -> only "Rendering todo #3" logs. The other 99 skip. ``` Each `TodoItem` receives a todo object from an immutable update (a new object only for the changed item, same references for the rest). PureComponent catches the unchanged references and skips those renders. ### The mutation trap This is the edge case that causes stale UI in production: ```tsx class UserCard extends React.PureComponent<{ user: { name: string; age: number } }> { render() { console.log('UserCard renders'); return <div>{this.props.user.name}, age {this.props.user.age}</div>; } } class App extends React.Component { state = { user: { name: 'Alice', age: 30 } }; updateAge = () => { // Wrong: mutate the existing object, then setState with the same reference this.state.user.age = 31; this.setState({ user: this.state.user }); // same reference! // PureComponent skips - UI shows age 30, actual value is 31 }; render() { return ( <> <UserCard user={this.state.user} /> <button onClick={this.updateAge}>Birthday</button> </> ); } } // Fix: this.setState({ user: { ...this.state.user, age: 31 } }) ``` The shallow check sees the same `user` reference and skips the render. The UI shows the old age. The fix is one line: spread the object to create a new reference.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.