Классовый компонент это класс JavaScript, который наследует React.Component и возвращает JSX из метода render(). Он читает пропсы из this.props, хранит состояние в this.state и обновляет его через this.setState(). В новом коде их заменили функциональные компоненты с хуками, но классы по-прежнему полностью поддерживаются, встречаются во многих старых проектах и остаются единственным способом написать границу ошибок.
Каждый счётчик хранит своё состояние. Добавьте третий <Counter label="Plums" />, и он тоже начнёт с 0.
Устройство классового компонента
import { Component } from 'react';
class Welcome extends Component {
static defaultProps = { name: 'stranger' };
constructor(props) {
super(props); // required before using this
this.state = { visits: 1 };
}
render() {
return <h1>Hello, {this.props.name}. Visit #{this.state.visits}</h1>;
}
}
- Класс наследует
Component(илиReact.Componentсimport React from 'react'). render()обязателен. Он должен быть чистым, как тело функционального компонента: читатьthis.propsиthis.stateи возвращать JSX.this.propsхранит пропсы. Они доступны только для чтения.- Состояние можно задать в
constructor(сначала вызовитеsuper(props)) или, как сейчас чаще, полем класса:state = { visits: 1 };. static defaultPropsпо-прежнему работает для классов в React 19 (его убрали только для функциональных компонентов).
this.setState объединяет и может принимать функцию обновления
setState делает две вещи иначе, чем сеттер useState. Он объединяет переданный объект с текущим состоянием, поэтому вы обновляете только названные ключи. И, как любое обновление состояния в React, он применяется не сразу, поэтому используйте форму с функцией обновления, когда следующее значение зависит от предыдущего.
«+3 with objects» добавляет один, потому что все три вызова читают одно и то же this.state.likes. «+3 with updaters» добавляет три. «Move to Paris» сохраняет name и likes (объединение), но теряет zip, потому что объединение работает только на один уровень. Напишите address: { ...this.state.address, city: 'Paris' }, чтобы его сохранить. Необязательный второй аргумент setState выполняется после обновления, и там консоль показывает новый адрес.
Привязка обработчиков событий
Метод, переданный как onClick={this.handleClick}, позже вызывается как обычная функция, без своего объекта, поэтому this внутри него равен undefined.
Первая кнопка выводит TypeError о чтении setState у undefined. Вторая работает, потому что стрелочная функция в поле класса захватывает this при создании экземпляра. Более старое решение, которое всё ещё часто встречается в унаследованном коде, привязывает в конструкторе:
constructor(props) {
super(props);
this.state = { on: false };
this.handleClick = this.handleClick.bind(this);
}
Стрелка прямо в строке, onClick={() => this.handleClick()}, тоже работает.
Методы жизненного цикла
Классы реагируют на монтирование, обновление и размонтирование через методы с фиксированными именами. Чаще всего вы увидите эти:
componentDidMount(): после того как первый рендер оказался в DOM. Запускайте таймеры, подписки, запросы.componentDidUpdate(prevProps, prevState): после каждого обновления. Сравнивайте с предыдущими значениями, прежде чем что-то делать, иначе получите цикл.componentWillUnmount(): перед удалением. Отмените то, что запустилcomponentDidMount.shouldComponentUpdate(nextProps, nextState): вернитеfalse, чтобы пропустить рендер.
Страница о жизненном цикле компонента содержит полный список, порядок выполнения и компонент, который выводит каждый метод.
Перевод класса в функциональный компонент
Вот класс, который использует все три распространённых метода жизненного цикла. Он тикает каждую секунду, выводит сообщение, когда меняется его пропс label, и останавливает таймер при удалении.
А вот тот же компонент в виде функции. Каждый метод жизненного цикла становится частью эффекта, а связанные настройка и очистка стоят рядом, а не в двух разных методах.
Оба таймера считают одинаково и выводят сообщение при каждой смене подписи. Версия-функция также выводит сообщение один раз при монтировании, потому что эффект выполняется и после первого рендера. Шаги для любого перевода:
this.props.xстановится деструктурированным пропсом,{ x }.- Каждый ключ
this.stateстановится отдельнымuseState. Помните, что сеттер заменяет, а не объединяет. - Методы становятся обычными функциями внутри компонента. Привязка не нужна.
componentDidMount,componentDidUpdateиcomponentWillUnmountстановятся вызовамиuseEffect, сгруппированными по тому, что они делают, а не по тому, когда выполняются.createRefстановитсяuseRef, аstatic contextTypeсthis.contextстановитсяuseContextилиuse.
Границы ошибок оставьте классами; функционального эквивалента у них нет.
PureComponent
Обычный классовый компонент рендерится каждый раз, когда рендерится его родитель. PureComponent сначала сравнивает новые пропсы и состояние с предыдущими на один уровень вглубь и пропускает рендер, когда ничего не изменилось. Это классовый аналог React.memo.
Нажмите кнопку: выводится только PlainLabel rendered, потому что PureLabel видит тот же text. Передайте text={'hello ' + clicks} обоим, и оба будут рендериться при каждом клике.
Сравнение поверхностное, поэтому пропс, который при каждом рендере родителя становится новым объектом или функцией (style={{ color: 'red' }}, onClick={() => ...}), сводит его на нет. Это та же ловушка, что и с React.memo.
Что React 19 убрал из классов
Если вы поддерживаете старый код на классах, несколько шаблонов в React 19 больше не работают:
- Строковые рефы (
ref="input"сthis.refs.input). ИспользуйтеcreateRef()или ref-колбэк. - Устаревший контекст (
contextTypes,childContextTypes,getChildContext). ИспользуйтеcreateContextсоstatic contextType. propTypesигнорируются. Используйте TypeScript или собственные проверки.findDOMNodeбольше нет. Вместо этого ставьте ref на элемент DOM.
Старые методы componentWillMount, componentWillReceiveProps и componentWillUpdate тоже устарели. Они всё ещё выполняются, и под старыми именами, и под именами с UNSAFE_ (UNSAFE_componentWillMount и так далее), но объявлены устаревшими, и StrictMode о них предупреждает; перенесите их код в componentDidMount, componentDidUpdate или getDerivedStateFromProps.
Часто задаваемые вопросы
Классовые компоненты в React устарели?
Нет. Они по-прежнему поддерживаются в React 19 и продолжат работать, но документация React рекомендует для нового кода функциональные компоненты с хуками. Для границ ошибок класс всё ещё нужен.
Чем классовые компоненты отличаются от функциональных?
Классовый компонент хранит состояние в this.state, обновляет его через this.setState и реагирует на жизненный цикл через именованные методы. Функциональный компонент использует для тех же задач хуки (useState, useEffect), обходится без this и короче.
setState обновляет состояние сразу?
Нет. this.setState планирует обновление, а React рендерит позже, поэтому сразу после вызова в this.state всё ещё старое значение. Передавайте функцию, this.setState((state) => ...), когда новое значение зависит от старого, или читайте результат в колбэке второго аргумента или в componentDidUpdate.
Почему this равен undefined в моём обработчике события?
Метод класса, переданный как onClick={this.handleClick}, вызывается без своего объекта, поэтому this равен undefined. Объявите обработчик как стрелочную функцию в поле класса (handleClick = () => { ... }) или привяжите его в конструкторе.
Что такое PureComponent?
Component, который пропускает рендер, когда его пропсы и состояние поверхностно равны предыдущим. Это классовая версия React.memo.