Documentation Index
Fetch the complete documentation index at: https://mintlify.com/preactjs/preact/llms.txt
Use this file to discover all available pages before exploring further.
PureComponent
A component class with a predefined shouldComponentUpdate implementation that performs shallow comparison of props and state.
Signature
abstract class PureComponent<P = {}, S = {}> extends Component<P, S> {
isPureReactComponent: boolean;
shouldComponentUpdate(nextProps: Readonly<P>, nextState: Readonly<S>): boolean;
}
Usage
Basic Example
Extend PureComponent instead of Component:
import { PureComponent } from 'preact/compat';
class UserCard extends PureComponent {
render() {
const { name, email, avatar } = this.props;
return (
<div className="user-card">
<img src={avatar} alt={name} />
<h3>{name}</h3>
<p>{email}</p>
</div>
);
}
}
// This component will only re-render when props change
With State
PureComponent also compares state changes:
import { PureComponent } from 'preact/compat';
class Counter extends PureComponent {
state = {
count: 0,
label: 'Counter'
};
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<h3>{this.state.label}</h3>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>+1</button>
</div>
);
}
}
TypeScript
Type your props and state:
import { PureComponent } from 'preact/compat';
interface TodoProps {
id: number;
text: string;
completed: boolean;
onToggle: (id: number) => void;
}
class TodoItem extends PureComponent<TodoProps> {
handleClick = () => {
this.props.onToggle(this.props.id);
};
render() {
const { text, completed } = this.props;
return (
<li
onClick={this.handleClick}
style={{ textDecoration: completed ? 'line-through' : 'none' }}
>
{text}
</li>
);
}
}
Implementation Details
The PureComponent implementation in Preact:
export function PureComponent(p, c) {
this.props = p;
this.context = c;
}
PureComponent.prototype = new Component();
PureComponent.prototype.isPureReactComponent = true;
PureComponent.prototype.shouldComponentUpdate = function (props, state) {
return shallowDiffers(this.props, props) || shallowDiffers(this.state, state);
};
Shallow Comparison
The shallowDiffers function checks if objects differ:
function shallowDiffers(a, b) {
for (let i in a) if (i !== '__source' && !(i in b)) return true;
for (let i in b) if (i !== '__source' && a[i] !== b[i]) return true;
return false;
}
This returns true if:
- Any keys exist in one object but not the other
- Any values differ using strict equality (
!==)
When to Use PureComponent
Good Use Cases ✅
- Components with simple props: Props that are primitives or stable references
- Frequently updated lists: List items that receive the same props often
- Performance optimization: Components that re-render unnecessarily
class ListItem extends PureComponent {
render() {
return <li>{this.props.text}</li>;
}
}
Problematic Cases ❌
- Props with new objects: Creating new objects on every render defeats the purpose
// Bad: Creates new object every render
<UserCard user={{ name: 'John', age: 30 }} />
// Good: Use stable reference
const user = { name: 'John', age: 30 };
<UserCard user={user} />
- Props with new arrays: New array references cause unnecessary re-renders
// Bad: Creates new array every render
<List items={this.state.data.map(x => x.name)} />
// Good: Memoize the array
const names = useMemo(
() => this.state.data.map(x => x.name),
[this.state.data]
);
<List items={names} />
- Props with inline functions: New function references on every render
// Bad: Creates new function every render
<Button onClick={() => this.handleClick(item.id)} />
// Good: Use class method or memoized callback
<Button onClick={this.handleClick} />
PureComponent vs Component
| Feature | Component | PureComponent |
|---|
shouldComponentUpdate | Not implemented | Shallow comparison |
| Re-renders | On any setState() or prop change | Only when props/state differ |
| Performance | Baseline | Faster for stable props |
| Use case | Most components | Frequently updated components |
PureComponent vs memo
- PureComponent: For class components
- memo: For functional components
// Class component
class UserCard extends PureComponent {
render() {
return <div>{this.props.name}</div>;
}
}
// Functional component
const UserCard = memo(({ name }) => (
<div>{name}</div>
));
Both provide similar optimization but for different component types.
Overriding shouldComponentUpdate
You can override shouldComponentUpdate in a PureComponent for custom logic:
class CustomPure extends PureComponent {
shouldComponentUpdate(nextProps, nextState) {
// Custom comparison logic
return this.props.userId !== nextProps.userId;
}
render() {
return <div>{this.props.userName}</div>;
}
}
Note: This defeats the purpose of PureComponent. Use regular Component instead.
Common Patterns
List Items
import { PureComponent } from 'preact/compat';
class TodoItem extends PureComponent {
render() {
const { todo, onToggle, onDelete } = this.props;
return (
<li>
<input
type="checkbox"
checked={todo.completed}
onChange={() => onToggle(todo.id)}
/>
<span>{todo.text}</span>
<button onClick={() => onDelete(todo.id)}>Delete</button>
</li>
);
}
}
class TodoList extends Component {
// Bind methods in constructor to maintain stable references
constructor(props) {
super(props);
this.handleToggle = this.handleToggle.bind(this);
this.handleDelete = this.handleDelete.bind(this);
}
handleToggle(id) {
// Toggle logic
}
handleDelete(id) {
// Delete logic
}
render() {
return (
<ul>
{this.state.todos.map(todo => (
<TodoItem
key={todo.id}
todo={todo}
onToggle={this.handleToggle}
onDelete={this.handleDelete}
/>
))}
</ul>
);
}
}
With Context
import { PureComponent, createContext } from 'preact/compat';
const ThemeContext = createContext('light');
class ThemedButton extends PureComponent {
static contextType = ThemeContext;
render() {
return (
<button className={`btn-${this.context}`}>
{this.props.children}
</button>
);
}
}
Identifying Pure Components
Check if a component is a PureComponent:
class MyComponent extends PureComponent {}
console.log(MyComponent.prototype.isPureReactComponent); // true
console.log(new MyComponent().isPureReactComponent); // true
Best Practices
- Stable Props: Ensure props are stable references or primitives
- Avoid Inline Objects: Don’t create new objects in render
- Avoid Inline Functions: Use class methods or memoized callbacks
- Measure Performance: Profile before and after to ensure it helps
- Consider Hooks: For new code, consider using functional components with
memo instead
Migration to Functional Components
Modern Preact/React development favors functional components with hooks:
// Before: Class with PureComponent
class UserCard extends PureComponent {
render() {
return <div>{this.props.name}</div>;
}
}
// After: Functional component with memo
import { memo } from 'preact/compat';
const UserCard = memo(({ name }) => (
<div>{name}</div>
));
Source
Implementation: compat/src/PureComponent.js:1-17