В React существует несколько способов обновления состояния компонента в зависимости от его типа (классовый или функциональный) и версии React. Рассмотрим основные подходы.
Для обновления состояния в классовых компонентах используется метод this.setState()
.
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
// Обновление с новым значением
this.setState({ count: this.state.count + 1 });
// Или с функцией обновления (updater function), если новое состояние зависит от предыдущего
this.setState(prevState => ({
count: prevState.count + 1
}));
}
render() {
return <button onClick={this.increment}>{this.state.count}</button>;
}
}
Важные нюансы:
setState
является асинхроннымthis.setState(updater, callback)
С появлением Hooks (хуков) в React 16.8, для управления состоянием используется хук useState
.
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increment = () => {
// Простое обновление
setCount(count + 1);
// Функциональное обновление, если новое состояние зависит от предыдущего
setCount(prevCount => prevCount + 1);
};
return <button onClick={increment}>{count}</button>;
}
Особенности useState
:
Object.is
) ререндер не происходитuseState
для разных частей состоянияДля более комплексного состояния или когда следующее состояние зависит от предыдущего в сложной логике.
import { useReducer } from 'react';
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<button onClick={() => dispatch({ type: 'increment' })}>
{state.count}
</button>
);
}
Иногда состояние нужно синхронизировать с пропсами (хотя это часто антипаттерн).
class EmailInput extends React.Component {
state = { email: this.props.defaultEmail };
componentDidUpdate(prevProps) {
if (this.props.defaultEmail !== prevProps.defaultEmail) {
this.setState({ email: this.props.defaultEmail });
}
}
// ...
}
Для предотвращения лишних ререндеров:
React.memo
для мемоизации компонентаuseMemo
/useCallback
для мемоизации значений и функций// НЕ ДЕЛАЙТЕ ТАК!
this.state.count = 1;
forceUpdate()
(почти всегда плохая практика)this.setState()
useState
или useReducer
Правильное обновление состояния - ключ к предсказуемому поведению React-приложений.