React.Component — основният клас за създаване на компоненти чрез наследяване в React. Преди появата на hooks във версия 16.8, класовите компоненти бяха единственият начин за управление на състоянието и жизнения цикъл. Според React, 2024, класовите компоненти все още се поддържат, въпреки че функционалните с hooks се препоръчват за нови проекти.
Основни точки
React.Component — абстрактен клас, който предоставя вградени методи за работа със състояние, props и жизнения цикъл на компонента. За да създадете класов компонент, трябва да дефинирате клас, който наследява React.Component, и да имплементирате метода render.
React.Component се появи в първата версия на React (2013) и остана основният начин за създаване на компоненти в продължение на пет години. Екосистемата на React беше изградена около класове: компоненти от по-висок ред (HOC), render props, контекст — всички тези модели бяха имплементирани чрез класов синтаксис.
С издаването на React 16.8 през 2019 г., екипът на React представи hooks като алтернатива на класовете. Hooks решаваха същите задачи — състояние, ефекти, контекст — но без наследяване и сложно обвързване на контекста. React.Component остава напълно поддържан, но за нови проекти се препоръчва функционалният подход.
Минималният класов компонент — клас с единствен метод render, който връща React елемент. render — единственият задължителен метод. Той трябва да бъде чиста функция на this.props и this.state: същият набор от props и състояние дава същия резултат.
import React, { Component } from 'react';
class Welcome extends Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Конструкторът се изпълнява преди монтирането. В него се извиква super(props) за предаване на props на родителския клас и се инициализира this.state. Използването на конструктора за други цели — абонаменти, API извиквания — не се препоръчва: за това съществува componentDidMount.
class Counter extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
return <p>Count: {this.state.count}</p>;
}
}
this.state — обектът, съдържащ данните на компонента. Директната промяна (this.state.count = 1) е забранена — не предизвиква повторно рендериране и нарушава предвидимостта. Състоянието трябва да се актуализира чрез this.setState, който създава нов обект на състоянието и задейства повторно рендериране.
setState може да приеме обект или функция. Функционалната форма е за предпочитане, когато новото състояние зависи от предишното: this.setState(prev => ({ count: prev.count + 1 })). React може да групира няколко извиквания на setState в един batch за оптимизиране на производителността.
class Toggle extends Component {
constructor(props) {
super(props);
this.state = { isOn: false };
}
handleClick() {
this.setState(prev => ({ isOn: !prev.isOn }));
}
render() {
return (
<button onClick={() => this.handleClick()}>
{this.state.isOn ? 'ON' : 'OFF'}
</button>
);
}
}
Важно свойство на setState — той е асинхронен. След извикване на setState, състоянието не се актуализира веднага. Ако трябва да извършите действие след актуализацията, предайте callback като втори аргумент: this.setState(newState, () => console.log(this.state)).
Класовите компоненти имат предефинирани методи, които React извиква в определени моменти. Монтиране — constructor → render → componentDidMount. Актуализиране — render → componentDidUpdate. Демонтиране — componentWillUnmount.
| Метод | Фаза | Предназначение |
|---|---|---|
| constructor | Монтиране | Инициализация на state и обвързване на методи |
| render | Всеки път | Връщане на React елементи (задължително) |
| componentDidMount | След монтиране | API заявки, абонаменти, таймери |
| componentDidUpdate | След актуализиране | Реакция на промяна на props/състояние |
| componentWillUnmount | Преди премахване | Почистване на абонаменти, таймери, отписване от събития |
componentDidMount — основното място за странични ефекти след първото рендериране. Тук се изпълняват HTTP заявки, установяват се WebSocket връзки и се стартират таймери. Ако не почистите абонамента в componentWillUnmount, възниква изтичане на памет.
class UserProfile extends Component {
componentDidMount() {
fetch(`/api/users/${this.props.userId}`)
.then(res => res.json())
.then(data => this.setState({ user: data }));
}
componentWillUnmount() {
// Отказ на заявката при демонтиране
}
render() {
return <div>{this.state.user?.name}</div>;
}
}
В JavaScript методите на класа по подразбиране не са обвързани с инстанцията. Ако предадете метод като callback — на манипулатор на събитие, таймер — this ще бъде undefined (в строг режим) или window (без строг режим). Без обвързване, this.setState ще хвърли грешка.
Съществуват три начина за обвързване: bind в конструктора, стрелкова функция в callback и class field със стрелкова функция. Първият начин — официалната препоръка на React: bind веднъж в конструктора, без повторно създаване на функцията при всяко рендериране.
// Метод 1: bind в конструктора (препоръчително)
class MyComponent extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({ clicked: true });
}
render() {
return <button onClick={this.handleClick}>Click</button>;
}
}
Class field — модерен синтаксис с автоматично обвързване. Стрелковата функция в свойството на класа улавя this от обхвата на видимост на конструктора. Недостатък — методът се създава на всяка инстанция, а не на прототипа, което увеличава паметта за стотици компоненти от един и същи тип.
Изборът между клас и функция — не е само въпрос на синтаксис. Функционалните компоненти с hooks решават проблеми, присъщи на класовете: дублиране на логика в различни методи на жизнения цикъл (componentDidMount + componentDidUpdate), сложност с this и невъзможност за извличане на свързана логика в многократно използваем блок.
Функционалните компоненти са по-лесни за тестване — те нямат вътрешно състояние (което преди hooks беше само в класове) и не изискват монтиране в DOM за проверка на callback. React препоръчва функционални компоненти за всички нови проекти, документацията и примерите се пишат с тях.
Класовите компоненти остават най-добрият избор при работа с наследен код. Ако проектът е започнат преди 2019 г., вероятно съдържа хиляди класови компоненти. Преписването им всички на hooks в един спринт е рисковано. React гарантира обратна съвместимост: класовите компоненти няма да бъдат премахнати.
Постепенната миграция започва с анализ на компонента. Простите компоненти без състояние (stateless) се превеждат първи — те тривиално се заменят с функции. След това — компоненти с едно-две полета за състояние, където useState директно заменя this.state и this.setState.
Сложните компоненти с множество методи на жизнения цикъл се превеждат чрез useEffect. Логиката от componentDidMount + componentDidUpdate се разделя на отделни useEffect с различни зависимости. componentWillUnmount се заменя с функция за връщане вътре в useEffect. За сложна логика на състоянието използвайте useReducer.
Инструментите за автоматична миграция — @phenomnomnominal/ts-react-class-to-hook или codemod скриптове — могат автоматично да конвертират прости класове. За сложни случаи миграцията остава ръчна работа, изискваща разбиране на логиката на оригиналния компонент.
Често задавани въпроси
Да. super(props) предава props на родителския React.Component. Без това извикване, this.props ще бъде undefined вътре в конструктора. В render и методите на жизнения цикъл, props са достъпни дори без super, но това е страничен ефект на имплементацията.
React групира няколко извиквания на setState в един batch за намаляване на броя на ненужните повторни рендерирания. Ако setState беше синхронен, всяко извикване би причинило незабавно рендериране, намалявайки производителността при масови актуализации.
Не. Hooks работят само във функционални компоненти. За проекти с класови компоненти са достъпни всички стари модели: render props, HOC и Consumer за контекст. Миграцията към hooks изисква преобразуване на класа във функция.
React.PureComponent имплементира shouldComponentUpdate с плитко (shallow) сравнение на props и състояние. За разлика от Component, който винаги пренарежда при setState, PureComponent пропуска пренареждането, ако данните не са се променили. Това е оптимизация за компоненти без сложно влагане.
Използвайте componentDidCatch и getDerivedStateFromError. componentDidCatch(error, info) регистрира грешката. getDerivedStateFromError актуализира state за показване на fallback-UI. Тези методи работят само в класови компоненти — функциите се нуждаят от обвиващ ErrorBoundary компонент.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също