- Spec files
npm-react
Describes: pkg:npm/react@18.3.x
- Description
- React is a JavaScript library for building user interfaces with declarative, component-based architecture.
- Author
- tessl
- Last updated
components.md docs/
1# Component Classes23React component classes provide the foundation for creating stateful class-based components with lifecycle methods. While function components with hooks are now preferred, class components remain important for certain use cases and legacy codebases.45## Capabilities67### Component89Base class for React class components providing state management and lifecycle methods.1011```javascript { .api }12/**13* Base class for React class components14*/15class Component<P = {}, S = {}, SS = any> {16/**17* Component constructor18* @param props - Component props19*/20constructor(props: P);2122/**23* Component props (read-only)24*/25readonly props: Readonly<P> & Readonly<{ children?: ReactNode }>;2627/**28* Component state29*/30state: Readonly<S>;3132/**33* Context value (legacy context API)34*/35context: any;3637/**38* Update component state39* @param partialState - Partial state update or updater function40* @param callback - Optional callback after state update41*/42setState<K extends keyof S>(43state: ((prevState: Readonly<S>, props: Readonly<P>) => Pick<S, K> | S | null) | Pick<S, K> | S | null,44callback?: () => void45): void;4647/**48* Force component re-render49* @param callback - Optional callback after update50*/51forceUpdate(callback?: () => void): void;5253/**54* Render method that returns JSX55* @returns React element or null56*/57render(): ReactNode;5859// Lifecycle methods60componentDidMount?(): void;61componentDidUpdate?(prevProps: Readonly<P>, prevState: Readonly<S>, snapshot?: SS): void;62componentWillUnmount?(): void;63shouldComponentUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: any): boolean;64getSnapshotBeforeUpdate?(prevProps: Readonly<P>, prevState: Readonly<S>): SS | null;6566// Error handling67componentDidCatch?(error: Error, errorInfo: ErrorInfo): void;68static getDerivedStateFromError?(error: Error): any;69static getDerivedStateFromProps?<P, S>(props: P, state: S): Partial<S> | null;70}71```7273**Usage Examples:**7475```javascript76import React, { Component } from 'react';7778class Counter extends Component {79constructor(props) {80super(props);81this.state = {82count: props.initialCount || 0,83lastUpdated: Date.now()84};85}8687componentDidMount() {88console.log('Counter component mounted');89// Set up timers, fetch data, etc.90}9192componentDidUpdate(prevProps, prevState) {93if (prevState.count !== this.state.count) {94console.log(`Count changed from ${prevState.count} to ${this.state.count}`);95}96}9798componentWillUnmount() {99console.log('Counter component will unmount');100// Clean up timers, subscriptions, etc.101}102103shouldComponentUpdate(nextProps, nextState) {104// Only update if count actually changed105return nextState.count !== this.state.count;106}107108handleIncrement = () => {109this.setState(prevState => ({110count: prevState.count + 1,111lastUpdated: Date.now()112}));113};114115handleDecrement = () => {116this.setState(prevState => ({117count: prevState.count - 1,118lastUpdated: Date.now()119}), () => {120console.log('State updated!');121});122};123124render() {125const { count, lastUpdated } = this.state;126const { title } = this.props;127128return (129<div>130<h2>{title}</h2>131<p>Count: {count}</p>132<p>Last updated: {new Date(lastUpdated).toLocaleTimeString()}</p>133<button onClick={this.handleIncrement}>+</button>134<button onClick={this.handleDecrement}>-</button>135</div>136);137}138}139140// Usage141<Counter title="My Counter" initialCount={5} />142```143144### PureComponent145146Optimized component class that implements shouldComponentUpdate with shallow prop and state comparison.147148```javascript { .api }149/**150* Component class with built-in shallow comparison optimization151*/152class PureComponent<P = {}, S = {}, SS = any> extends Component<P, S, SS> {153/**154* Automatically implements shouldComponentUpdate with shallow comparison155* Only re-renders if props or state have shallowly changed156*/157}158```159160**Usage Examples:**161162```javascript163import React, { PureComponent } from 'react';164165class UserCard extends PureComponent {166render() {167const { user, onEdit } = this.props;168169console.log('UserCard rendering'); // Only logs when props change170171return (172<div className="user-card">173<img src={user.avatar} alt={user.name} />174<h3>{user.name}</h3>175<p>{user.email}</p>176<button onClick={() => onEdit(user.id)}>Edit</button>177</div>178);179}180}181182class UserList extends PureComponent {183state = {184users: [185{ id: 1, name: 'John', email: 'john@example.com', avatar: 'john.jpg' },186{ id: 2, name: 'Jane', email: 'jane@example.com', avatar: 'jane.jpg' }187],188selectedId: null189};190191handleEdit = (userId) => {192this.setState({ selectedId: userId });193};194195render() {196const { users, selectedId } = this.state;197198return (199<div>200<h2>Users</h2>201{users.map(user => (202<UserCard203key={user.id}204user={user}205onEdit={this.handleEdit}206isSelected={user.id === selectedId}207/>208))}209</div>210);211}212}213```214215### Error Boundaries216217Components that catch JavaScript errors in their child component tree and display fallback UI.218219```javascript { .api }220/**221* Error boundary lifecycle methods222*/223interface ErrorBoundaryMethods {224/**225* Catch errors during rendering, lifecycle methods, and constructors226* @param error - The error that was thrown227* @param errorInfo - Information about the error228*/229componentDidCatch?(error: Error, errorInfo: ErrorInfo): void;230231/**232* Update state in response to an error233* @param error - The error that was thrown234* @returns New state or null235*/236static getDerivedStateFromError?(error: Error): any;237}238239interface ErrorInfo {240componentStack: string;241}242```243244**Usage Examples:**245246```javascript247import React, { Component } from 'react';248249class ErrorBoundary extends Component {250constructor(props) {251super(props);252this.state = {253hasError: false,254error: null,255errorInfo: null256};257}258259static getDerivedStateFromError(error) {260// Update state to show fallback UI261return { hasError: true };262}263264componentDidCatch(error, errorInfo) {265console.error('Error caught by boundary:', error);266console.error('Error info:', errorInfo);267268this.setState({269error: error,270errorInfo: errorInfo271});272273// Log error to error reporting service274logErrorToService(error, errorInfo);275}276277render() {278if (this.state.hasError) {279return (280<div className="error-boundary">281<h2>Something went wrong.</h2>282<details style={{ whiteSpace: 'pre-wrap' }}>283{this.state.error && this.state.error.toString()}284<br />285{this.state.errorInfo.componentStack}286</details>287<button onClick={() => this.setState({ hasError: false, error: null, errorInfo: null })}>288Try again289</button>290</div>291);292}293294return this.props.children;295}296}297298// Problem component that might throw299class ProblematicComponent extends Component {300constructor(props) {301super(props);302this.state = { counter: 0 };303}304305handleClick = () => {306this.setState(({ counter }) => {307if (counter === 5) {308throw new Error('Counter reached 5!');309}310return { counter: counter + 1 };311});312};313314render() {315return (316<div>317<p>Counter: {this.state.counter}</p>318<button onClick={this.handleClick}>Increment</button>319</div>320);321}322}323324// Usage with error boundary325function App() {326return (327<div>328<h1>My App</h1>329<ErrorBoundary>330<ProblematicComponent />331</ErrorBoundary>332</div>333);334}335```336337### Lifecycle Methods338339Complete reference for React class component lifecycle methods.340341```javascript { .api }342/**343* Component lifecycle methods344*/345interface ComponentLifecycle<P, S, SS = any> {346// Mounting347constructor?(props: P);348componentDidMount?(): void;349350// Updating351shouldComponentUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: any): boolean;352getSnapshotBeforeUpdate?(prevProps: Readonly<P>, prevState: Readonly<S>): SS | null;353componentDidUpdate?(prevProps: Readonly<P>, prevState: Readonly<S>, snapshot?: SS): void;354355// Unmounting356componentWillUnmount?(): void;357358// Error handling359componentDidCatch?(error: Error, errorInfo: ErrorInfo): void;360361// Static methods362static getDerivedStateFromProps?<P, S>(props: P, state: S): Partial<S> | null;363static getDerivedStateFromError?(error: Error): any;364}365```366367**Usage Examples:**368369```javascript370import React, { Component } from 'react';371372class DataFetcher extends Component {373constructor(props) {374super(props);375this.state = {376data: null,377loading: false,378error: null379};380}381382// Static method to update state based on props383static getDerivedStateFromProps(nextProps, prevState) {384// Reset data when URL changes385if (nextProps.url !== prevState.previousUrl) {386return {387data: null,388loading: false,389error: null,390previousUrl: nextProps.url391};392}393return null;394}395396// Called once after component mounts397componentDidMount() {398this.fetchData();399}400401// Called when props or state change402componentDidUpdate(prevProps, prevState) {403// Fetch new data if URL changed404if (prevProps.url !== this.props.url) {405this.fetchData();406}407}408409// Called before component unmounts410componentWillUnmount() {411// Cancel any pending requests412if (this.abortController) {413this.abortController.abort();414}415}416417// Optimize re-renders418shouldComponentUpdate(nextProps, nextState) {419return (420nextProps.url !== this.props.url ||421nextState.data !== this.state.data ||422nextState.loading !== this.state.loading ||423nextState.error !== this.state.error424);425}426427// Capture values before update428getSnapshotBeforeUpdate(prevProps, prevState) {429// Preserve scroll position if data was loading430if (prevState.loading && !this.state.loading) {431return window.scrollY;432}433return null;434}435436fetchData = async () => {437this.setState({ loading: true, error: null });438439try {440this.abortController = new AbortController();441const response = await fetch(this.props.url, {442signal: this.abortController.signal443});444445if (!response.ok) {446throw new Error(`HTTP error! status: ${response.status}`);447}448449const data = await response.json();450this.setState({ data, loading: false });451} catch (error) {452if (error.name !== 'AbortError') {453this.setState({ error: error.message, loading: false });454}455}456};457458render() {459const { data, loading, error } = this.state;460461if (loading) return <div>Loading...</div>;462if (error) return <div>Error: {error}</div>;463if (!data) return <div>No data</div>;464465return (466<div>467<h2>Data:</h2>468<pre>{JSON.stringify(data, null, 2)}</pre>469</div>470);471}472}473474// Usage475<DataFetcher url="https://api.example.com/users" />476```477478## Types479480```javascript { .api }481// Component class types482interface ComponentClass<P = {}, S = ComponentState> extends StaticLifecycle<P, S> {483new (props: P, context?: any): Component<P, S>;484contextType?: Context<any>;485defaultProps?: Partial<P>;486displayName?: string;487}488489// Props with children490type PropsWithChildren<P> = P & { children?: ReactNode };491492// Error info for error boundaries493interface ErrorInfo {494componentStack: string;495}496497// State type498type ComponentState = any;499```