В чем разница между классовыми компонентами и компонентами на React Hooks?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между классовыми компонентами и React Hooks
Введение
Долгое время в React были только классовые компоненты. С версии 16.8 (2019) появились Hooks, которые позволяют использовать state и другие возможности React в функциональных компонентах.
Классовые компоненты (Class Components)
Классовый компонент расширяет React.Component и имеет методы жизненного цикла:
import React from 'react';
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
componentDidMount() {
console.log('Компонент загрузился');
}
componentDidUpdate(prevProps, prevState) {
console.log('Компонент обновился');
}
componentWillUnmount() {
console.log('Компонент будет удален');
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Увеличить
</button>
</div>
);
}
}
export default Counter;
Характеристики:
- Используют this и методы жизненного цикла
- State инициализируется в constructor
- Методы жизненного цикла разделены по назначению
- Требуют привязки методов (bind)
Функциональные компоненты с Hooks
С Hooks функциональные компоненты получили те же возможности:
import React, { useState, useEffect } from 'react';
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('Компонент загрузился или обновился');
return () => {
console.log('Cleanup перед обновлением или удалением');
};
}, [count]);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Увеличить
</button>
</div>
);
}
export default Counter;
Характеристики:
- Простые функции
- Нет this
- useState для управления state
- useEffect для побочных эффектов
- Более читаемый код
Сравнительная таблица
| Аспект | Классовые компоненты | Hooks (функциональные) |
|---|---|---|
| Синтаксис | class Component extends React.Component | function Component() |
| State | this.state, this.setState() | useState() |
| Побочные эффекты | componentDidMount, componentDidUpdate | useEffect() |
| Очистка | componentWillUnmount | return () => {} в useEffect |
| Контекст | this.context | useContext() |
| Читаемость | Более многословно | Более компактно |
| Производительность | Нормальная | Обычно быстрее |
| Привязка методов | Нужен bind() или стрелки | Не требуется |
Практические примеры
1. Управление Multiple State
Class Component:
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
email: '',
age: ''
};
}
handleChange = (e) => {
const { name, value } = e.target;
this.setState({ [name]: value });
};
render() {
return (
<form>
<input name="name" value={this.state.name} onChange={this.handleChange} />
<input name="email" value={this.state.email} onChange={this.handleChange} />
<input name="age" value={this.state.age} onChange={this.handleChange} />
</form>
);
}
}
Hooks:
function Form() {
const [form, setForm] = useState({ name: '', email: '', age: '' });
const handleChange = (e) => {
const { name, value } = e.target;
setForm({ ...form, [name]: value });
};
return (
<form>
<input name="name" value={form.name} onChange={handleChange} />
<input name="email" value={form.email} onChange={handleChange} />
<input name="age" value={form.age} onChange={handleChange} />
</form>
);
}
2. API запросы
Class Component:
class UserList extends React.Component {
state = { users: [], loading: true, error: null };
componentDidMount() {
fetch('/api/users')
.then(res => res.json())
.then(users => this.setState({ users, loading: false }))
.catch(error => this.setState({ error, loading: false }));
}
render() {
const { users, loading, error } = this.state;
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}
}
Hooks:
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch('/api/users')
.then(res => res.json())
.then(users => { setUsers(users); setLoading(false); })
.catch(error => { setError(error); setLoading(false); });
}, []);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}
3. Фильтрация данных
Class Component:
class FilteredList extends React.Component {
constructor(props) {
super(props);
this.state = { items: [1, 2, 3, 4, 5], filter: '' };
}
render() {
const filtered = this.state.items.filter(
i => i.toString().includes(this.state.filter)
);
return (
<div>
<input
value={this.state.filter}
onChange={e => this.setState({ filter: e.target.value })}
/>
<ul>{filtered.map(i => <li key={i}>{i}</li>)}</ul>
</div>
);
}
}
Hooks:
function FilteredList() {
const [items] = useState([1, 2, 3, 4, 5]);
const [filter, setFilter] = useState('');
const filtered = useMemo(
() => items.filter(i => i.toString().includes(filter)),
[items, filter]
);
return (
<div>
<input value={filter} onChange={e => setFilter(e.target.value)} />
<ul>{filtered.map(i => <li key={i}>{i}</li>)}</ul>
</div>
);
}
Кастомные Hooks
Hooks позволяют создавать переиспользуемую логику:
// Кастомный Hook для API запросов
function useApi(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(data => { setData(data); setLoading(false); })
.catch(error => { setError(error); setLoading(false); });
}, [url]);
return { data, loading, error };
}
// Использование
function App() {
const { data: users, loading, error } = useApi('/api/users');
if (loading) return <div>Loading...</div>;
return <div>{users?.map(u => <div key={u.id}>{u.name}</div>)}</div>;
}
В классовых компонентах аналогичная логика требовала использования HOC или render props.
Преимущества Hooks
- Более компактный и читаемый код
- Легче переиспользовать логику (кастомные Hooks)
- Проще избежать проблем с this
- Лучше оптимизируется бандлер
- Нет необходимости в привязке методов
Когда использовать классовые компоненты
- Error Boundaries (пока нет Hook'а для этого)
- Наследование (не рекомендуется, но возможно)
- Старый код (миграция не обязательна)
Современный подход
Сегодня React сообщество переходит на функциональные компоненты с Hooks, а классовые компоненты считаются устаревшим паттерном.
Выводы
Hooks предоставляют более удобный и современный способ написания React компонентов. Они делают код более читаемым, улучшают переиспользование логики и становятся стандартом в новых проектах. Классовые компоненты остаются поддерживаемыми, но не рекомендуются для новых разработок.