useReducer для сложной логики состояния
Хук useReducer — это альтернатива useState для случаев, когда логика обновления состояния становится сложной: много подсостояний, взаимозависимые значения или множество возможных действий. Он основан на концепции редюсера из Flux/Redux и хорошо подходит для управления состоянием корзины, формы с валидацией, истории навигации и других сценариев.
Основы useReducer
Функция useReducer принимает два аргумента:
- редюсер (функцию, которая описывает, как состояние меняется в ответ на действия),
- начальное состояние.
Она возвращает текущее состояние и функцию dispatch, которая отправляет действия в редюсер:
const [state, dispatch] = useReducer(reducer, initialState);
Структура редюсера
Редюсер — это чистая функция, принимающая текущее состояние и действие (action), и возвращающая новое состояние:
type Action =
| { type: 'ADD_ITEM'; payload: string }
| { type: 'REMOVE_ITEM'; payload: number };
type State = {
items: string[];
};
function cartReducer(state: State, action: Action): State {
switch (action.type) {
case 'ADD_ITEM':
return { ...state, items: [...state.items, action.payload] };
case 'REMOVE_ITEM':
return {
...state,
items: state.items.filter((_, index) => index !== action.payload),
};
default:
return state;
}
}
Пример использования
import { useReducer } from 'react';
import { View, Text, Button } from 'react-native';
export default function CartScreen() {
const [state, dispatch] = useReducer(cartReducer, { items: [] });
return (
<View>
<Text>Товаров: {state.items.length}</Text>
<Button
title="Добавить товар"
onPress={() => dispatch({ type: 'ADD_ITEM', payload: 'Новый товар' })}
/>
{state.items.map((item, index) => (
<Button
key={index}
title={`Удалить ${item}`}
onPress={() => dispatch({ type: 'REMOVE_ITEM', payload: index })}
/>
))}
</View>
);
}
Преимущества useReducer
- Централизованная логика обновления состояния.
- Легче тестировать и отлаживать: каждое действие явно описано.
- Упрощает управление состоянием с несколькими подполями.
Когда выбирать useReducer вместо useState
Используйте useReducer, если:
- состояние содержит несколько связанных значений,
- следующее состояние зависит от предыдущего,
- у вас есть сложная логика обновления (например, форма с полями, зависящими друг от друга),
- вы хотите улучшить читаемость кода за счёт декларативного описания изменений.
В простых случаях (одиночные значения, независимые флаги) достаточно useState.