Если открыть старый React-код, там почти наверняка будут class-компоненты. Если открыть новый туториал, там почти наверняка будут hooks. Поэтому вопрос обычно звучит не как «что такое hooks», а как «что мне делать со своим кодом прямо сейчас».
Короткий ответ такой: для нового React-кода hooks давно стали базовым выбором, но class-компоненты по-прежнему важно понимать, если ты работаешь с легаси-кодом, миграциями или boundary-слоями вокруг ошибок.
Если убрать идеологию, решение обычно сводится к трем правилам: новый код пиши на hooks, старый код не переписывай без повода, а class-компоненты держи в голове как часть реального React-наследия, а не как тему “из прошлого”.
Какой из них использовать
Официальная позиция команды React (согласно документации):
When you’re ready, we’d encourage you to start trying Hooks in new components you write. […] We don’t recommend rewriting your existing classes to Hooks unless you planned to rewrite them anyway (e.g. to fix bugs).
Итог:
- новый код должен использовать функциональные компоненты с хуками;
- старый код может продолжать использовать компоненты класса, если ты не хочешь переписывать.
Должен ли я тогда сосредоточиться на хуках?
Это не так просто.
Тебе по-прежнему нужны class-компоненты для Error Boundaries. Можно найти библиотеку на основе хуков, но незнание механизма не оправдывает лишнюю зависимость.
Вдобавок ко всему, большая часть кода, написанного до 2019 года, скорее всего, по-прежнему будет использовать компоненты класса, поскольку нет необходимости немедленно переписывать их в функциональные компоненты с помощью хуков. Если ты хочешь понять существующий код, тебе будет необходимо изучить компоненты класса.
Также ты обнаружишь, что компании, которые задают вопросы по React во время собеседований, по-прежнему будут спрашивать о классах.
Нужно ли переписать старый код на основе классов для использования хуков
Как и во всем хорошем, здесь есть компромиссы.
Хуки приводят к гораздо более чистым и легким для понимания компонентам по сравнению с компонентами классов аналогичной сложности.
Для сравнения: один и тот же компонент, который запрашивает данные из Star Wars API, — сначала как класс, затем как функциональный с хуками:
import React from 'react';
export default class DataDisplayer extends React.Component {
constructor(props) {
super(props);
this.state = {
data: null,
};
}
async componentDidMount() {
const response = await fetch(
`https://swapi.dev/api/people/${this.props.id}/`
);
const newData = await response.json();
this.setState({ data: newData });
}
render() {
const { data } = this.state;
if (data) {
return <div>{data.name}</div>;
} else {
return null;
}
}
}По мере роста приложения методы жизненного цикла становятся больше, и увеличивается переключение контекста, связанное только с прокруткой файла.
Не знаю, как у тебя, но мой мыслительный процесс при просмотре классов такой:
-
хорошо, я нахожусь в
componentDidMount, поэтому буду получать данные здесь; -
выполняем рендеринг, поэтому этот код запускается каждый раз;
-
нужно добавить дополнительную функциональность … хм, какой метод жизненного цикла снова используется?.
С другой стороны, есть хуки:
import React, { useEffect, useState } from 'react';
export default function DataDisplayer(props) {
const [data, setData] = useState('');
useEffect(() => {
const getData = async () => {
const response = await fetch(`https://swapi.dev/api/people/${props.id}/`);
const newData = await response.json();
setData(newData);
};
getData();
}, [props.id]);
if (data) {
return <div>{data.name}</div>;
} else {
return null;
}
}С помощью хуков написание кода намного проще, и я считаю, что чтение функциональных компонентов с помощью хуков требует меньшего переключения контекста, поскольку ты не прыгаешь по файлу, чтобы определить, в каком методе жизненного цикла, по твоему мнению, что-то произошло.
Это главное преимущество переписывания: понять, что делает компонент, становится быстрее.
Главный недостаток - время; время, потраченное на переписывание, - это время, которое ты мог бы потратить на создание новых функций или написание интеграционных тестов.
Что дальше делать
Я рекомендую следующий подход, который обычно дает лучший баланс:
- весь новый код писать как функциональные компоненты с hooks;
- существующий код переписывать только тогда, когда это совпадает с задачей: исправление ошибки, расширение логики, упрощение тестов;
- class-компоненты не демонизировать, а понимать их настолько, чтобы спокойно поддерживать легаси и boundary-слои.
Итог
Если тебе нужен практичный ориентир, он простой: новый код пиши на hooks, старый переписывай только там, где это окупается вместе с задачей. Такой подход обычно дает лучший баланс между качеством кода и стоимостью изменений.
Самая дорогая ошибка здесь - переписывать классы просто потому, что они “старые”. Самая полезная привычка - каждый раз спрашивать, улучшит ли миграция читаемость, тестируемость и скорость дальнейших изменений именно в этом месте кода.