Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI21 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что Hooks внесли в React
Появление Hooks в React 16.8 (февраль 2019) было революционным изменением, которое полностью трансформировало экосистему React. Это не просто синтаксический сахар - это переосмысление того, как мы пишем React компоненты.
До Hooks: Эра компонентов-классов
Проблемы, которые были
// Логика разбросана по жизненным циклам
class UserProfile extends React.Component {
componentDidMount() {
// Подписаться на изменения пользователя
this.unsubscribe = store.subscribe(this.updateUser);
// Загрузить дополнительные данные
this.fetchData();
// Настроить таймер
this.timer = setInterval(() => {
this.checkUpdates();
}, 5000);
}
componentDidUpdate(prevProps) {
// Повторить логику, если user изменился
if (prevProps.userId !== this.props.userId) {
this.fetchData();
}
}
componentWillUnmount() {
// Очистить ВСЕ, что создавали выше (сложно не забыть)
this.unsubscribe();
clearInterval(this.timer);
}
render() {
return <div>{this.state.user.name}</div>;
}
}
Проблемы:
- Связанная логика разбросана по разным методам
- Сложно найти все place, где обновляется состояние
- Легко забыть cleanup в componentWillUnmount
- Трудно переиспользовать логику между компонентами
- Много boilerplate кода (constructor, super, this binding)
После Hooks: Логика по функциональности
function UserProfile({ userId }) {
// Управление пользователем
const [user, setUser] = useState(null);
useEffect(() => {
const unsubscribe = store.subscribe(() => {
setUser(store.getState().user);
});
return () => unsubscribe(); // Cleanup
}, []);
// Загрузка данных
useEffect(() => {
fetchUserData(userId).then(setUser);
}, [userId]); // Автоматически переупорядочивается если userId изменился
// Таймер
useEffect(() => {
const timer = setInterval(() => {
checkUpdates();
}, 5000);
return () => clearInterval(timer); // Cleanup
}, []);
return <div>{user?.name}</div>;
}
Преимущества:
- Каждый useEffect - отдельная логика
- Cleanup находится рядом с логикой
- Автоматическое переупорядочивание благодаря зависимостям
- Меньше кода
Что именно Hooks изменили
1. Переиспользование логики (Custom Hooks)
Раньше (Render Props, Higher Order Components):
// Очень сложно и громоздко
function withTheme(Component) {
return (props) => (
<ThemeContext.Consumer>
{theme => <Component {...props} theme={theme} />
</ThemeContext.Consumer>
);
}
const ThemedButton = withTheme(Button);
// Если нужны несколько HOC - наступает HOC Hell
const Component = withAuth(withTheme(withData(MyComponent)));
Сейчас (Custom Hooks):
// Просто функция, которую можно переиспользовать
function useTheme() {
return useContext(ThemeContext);
}
function useAuth() {
const [user, setUser] = useState(null);
// логика аутентификации
return { user, login, logout };
}
// Использование - просто вызвать хуки
function MyComponent() {
const theme = useTheme();
const { user, login } = useAuth();
// ...
}
2. Управление состоянием (State Management)
Раньше:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
Count: {this.state.count}
<button onClick={this.increment}>+</button>
</div>
);
}
}
Сейчас:
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
Count: {count}
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
// Или с useReducer для сложного состояния
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
// ...
}
3. Функциональные компоненты стали мощнее классов
Раньше:
- Функциональные компоненты были ограничены (только props)
- Нужны были классы для состояния и побочных эффектов
Сейчас:
- Функциональные компоненты имеют все возможности классов
- Плюс дополнительные преимущества (легче тестировать, менее verbose)
4. Производительность
// useCallback - мемоизация функций
const handleClick = useCallback(() => {
// функция не пересоздается, если deps не изменились
}, [deps]);
// useMemo - мемоизация вычислений
const expensiveValue = useMemo(() => {
return computeExpensive(data);
}, [data]);
// Раньше нужны были сложные оптимизации
// shouldComponentUpdate, PureComponent
5. Тестирование
Раньше - сложно:
// Нужно: mount компонент, вызывать методы, проверять this.state
import { mount } from 'enzyme';
const wrapper = mount(<Counter />);
wrapper.find('button').simulate('click');
expect(wrapper.find('.count').text()).toBe('1');
Сейчас - просто:
// Тестируем хук отдельно
import { renderHook, act } from '@testing-library/react';
import { useCounter } from './useCounter';
const { result } = renderHook(() => useCounter());
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
Экосистемные изменения
1. Появились новые library patterns
// До: всё базировалось на HOC и Render Props
// Сейчас: простые hook-based библиотеки
// react-query (данные)
const { data, isLoading } = useQuery('users', fetchUsers);
// zustand (состояние)
const count = useStore((state) => state.count);
// react-hook-form (формы)
const { register, handleSubmit } = useForm();
2. Меньше нужно знать для начинающих
// Раньше нужно было понимать:
// - this binding
// - жизненные циклы
// - классы в JavaScript
// - разница между constructor и componentDidMount
// Сейчас начинающий может писать:
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
// побочные эффекты
}, [count]);
return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
}
// Готово! Не нужно знать про классы.
3. Миграция экосистемы
// Большинство популярных библиотек переработали API на hooks:
// - React Router (useParams, useHistory, useLocation)
// - Redux (useDispatch, useSelector)
// - GraphQL (useQuery, useMutation)
// - Axios/Fetch (useQuery, useFetch)
// Старый способ (React Router v5):
const params = this.props.match.params;
const history = this.props.history;
// Новый (React Router v6):
const params = useParams();
const navigate = useNavigate();
Глубокие изменения
1. Способ думать о компонентах
Раньше: Компонент = класс с жизненными циклами
class User extends React.Component {
componentDidMount() { }
componentDidUpdate() { }
componentWillUnmount() { }
render() { }
}
Сейчас: Компонент = функция, которая возвращает UI
function User() {
// состояние
// побочные эффекты
// логика
return UI;
}
2. Направление данных
Раньше: Props вниз, callbacks вверх (сложно)
// Нужно проходить через все компоненты
<App>
<Parent onUpdate={handleUpdate}>
<Child onUpdate={onUpdate} />
</Parent>
</App>
Сейчас: Context API + Hooks (просто)
const UserContext = createContext();
function App() {
const [user, setUser] = useState();
return (
<UserContext.Provider value={{ user, setUser }}>
<AnyComponent /> {/* может доступ к user отсюда */}
</UserContext.Provider>
);
}
function AnyComponent() {
const { user, setUser } = useContext(UserContext);
}
Статистика
- В 2024 году 95%+ новых React проектов используют только функциональные компоненты с hooks
- Классы считаются "legacy" паттерном
- Большинство tutorials и документации сфокусированы на hooks
Итого
Hooks внесли:
- Логика по функциональности - связанная логика в одном месте
- Переиспользование - простые кастомные хуки вместо HOC
- Доступность - проще для новичков
- Производительность - встроенная мемоизация
- Тестируемость - проще тестировать
- Экосистема - все библиотеки переделали API
- Будущее React - React Suspense, Concurrent Rendering основаны на Hooks
Это был переломный момент в истории React. Сейчас сложно представить React без Hooks.