Base class for creating stateful, class-based components in Preact.
Signature
abstract class Component<P = {}, S = {}> {
constructor(props?: P, context?: any);
// Instance properties
props: RenderableProps<P>;
state: Readonly<S>;
context: any;
// Core methods
setState<K extends keyof S>(
state: ((prevState: Readonly<S>, props: Readonly<P>) => Pick<S, K> | Partial<S> | null) | (Pick<S, K> | Partial<S> | null),
callback?: () => void
): void;
forceUpdate(callback?: () => void): void;
abstract render(
props?: RenderableProps<P>,
state?: Readonly<S>,
context?: any
): ComponentChildren;
// Lifecycle methods
componentWillMount?(): void;
componentDidMount?(): void;
componentWillUnmount?(): void;
componentWillReceiveProps?(nextProps: Readonly<P>, nextContext: any): void;
shouldComponentUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: any): boolean;
componentWillUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: any): void;
getSnapshotBeforeUpdate?(oldProps: Readonly<P>, oldState: Readonly<S>): any;
componentDidUpdate?(previousProps: Readonly<P>, previousState: Readonly<S>, snapshot: any): void;
componentDidCatch?(error: any, errorInfo: ErrorInfo): void;
getChildContext?(): object;
// Static methods
static displayName?: string;
static contextType?: Context<any>;
static getDerivedStateFromProps?(props: Readonly<object>, state: Readonly<object>): object | null;
static getDerivedStateFromError?(error: any): object | null;
}
Type Parameters
The props type for the component.
The state type for the component.
Constructor
constructor(props?: P, context?: any)
Creates a new component instance with the given props and context.
Instance Properties
props
props: RenderableProps<P>
The current props passed to the component. Includes children and optional ref.
state
The current state of the component. Should only be modified via setState().
context
Context value from the nearest Provider ancestor, or the default value.
Core Methods
setState
setState<K extends keyof S>(
state: ((prevState: Readonly<S>, props: Readonly<P>) => Pick<S, K> | Partial<S> | null) | (Pick<S, K> | Partial<S> | null),
callback?: () => void
): void
Updates component state and schedules a re-render.
Parameters:
state: Object to merge into state, or updater function receiving previous state and props
callback: Optional function called after state update and re-render complete
Implementation: src/component.js:34
forceUpdate
forceUpdate(callback?: () => void): void
Forces a synchronous re-render, bypassing shouldComponentUpdate.
Parameters:
callback: Optional function called after re-render completes
Implementation: src/component.js:69
render
abstract render(
props?: RenderableProps<P>,
state?: Readonly<S>,
context?: any
): ComponentChildren
Returns the component’s virtual DOM tree. Must be implemented by subclasses.
Usage Examples
Basic Component
import { Component } from 'preact';
class Counter extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Increment
</button>
</div>
);
}
}
With TypeScript
import { Component } from 'preact';
interface Props {
initialCount: number;
onCountChange?: (count: number) => void;
}
interface State {
count: number;
}
class Counter extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { count: props.initialCount };
}
increment = () => {
this.setState(
(prevState) => ({ count: prevState.count + 1 }),
() => {
this.props.onCountChange?.(this.state.count);
}
);
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
Lifecycle Methods
import { Component } from 'preact';
class DataFetcher extends Component {
state = { data: null, loading: true, error: null };
componentDidMount() {
// Fetch data after mount
fetch('/api/data')
.then(res => res.json())
.then(data => this.setState({ data, loading: false }))
.catch(error => this.setState({ error, loading: false }));
}
componentWillUnmount() {
// Cleanup subscriptions, timers, etc.
this.cleanup();
}
componentDidUpdate(prevProps, prevState) {
// Respond to prop or state changes
if (prevProps.id !== this.props.id) {
this.fetchData(this.props.id);
}
}
render() {
const { data, loading, error } = this.state;
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>{JSON.stringify(data)}</div>;
}
}
shouldComponentUpdate Optimization
import { Component } from 'preact';
class OptimizedList extends Component {
shouldComponentUpdate(nextProps, nextState) {
// Only re-render if items array reference changed
return this.props.items !== nextProps.items;
}
render() {
return (
<ul>
{this.props.items.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
}
Error Boundaries
import { Component } from 'preact';
class ErrorBoundary extends Component {
state = { hasError: false, error: null };
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
// Log error to service
console.error('Error caught:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div>
<h1>Something went wrong</h1>
<details>
<summary>Error details</summary>
<pre>{this.state.error.toString()}</pre>
</details>
</div>
);
}
return this.props.children;
}
}
Context Consumer
import { Component, createContext } from 'preact';
const ThemeContext = createContext('light');
class ThemedButton extends Component {
static contextType = ThemeContext;
render() {
const theme = this.context;
return (
<button className={`button-${theme}`}>
{this.props.children}
</button>
);
}
}
Lifecycle Method Order
Mounting
constructor()
static getDerivedStateFromProps()
render()
componentDidMount()
Updating
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
Unmounting
componentWillUnmount()
Error Handling
static getDerivedStateFromError()
componentDidCatch()
Legacy Lifecycle Methods
These methods are still supported but deprecated:
componentWillMount() - Use componentDidMount() or constructor()
componentWillReceiveProps() - Use getDerivedStateFromProps() or componentDidUpdate()
componentWillUpdate() - Use getSnapshotBeforeUpdate() or componentDidUpdate()
Implementation Details
The Component class is implemented in src/component.js:19 as BaseComponent:
export function BaseComponent(props, context) {
this.props = props;
this.context = context;
this._bits = 0;
}
BaseComponent.prototype.setState = function (update, callback) {
// Implementation...
};
BaseComponent.prototype.forceUpdate = function (callback) {
// Implementation...
};
BaseComponent.prototype.render = Fragment;
setState uses shallow merging and batches multiple calls
- Re-renders are scheduled asynchronously via microtasks
forceUpdate bypasses shouldComponentUpdate optimization
- State updates within
setState callback see the updated state
render - Mount components to the DOM
Fragment - Group multiple children
createContext - Create context for component tree
hooks - Modern alternative to class components