PassFront
  1. PassFront
  2. База знаний
  3. Хуки

В чем разница между useState и useReducer?

Хуки

Оба хука хранят состояние; разница — в способе обновления: useState — прямые сеттеры, useReducer — централизованная функция-редьюсер, обрабатывающая действия.

useState

const [count, setCount] = useState(0);
setCount(count + 1);

Минимум кода; логика обновления живёт в местах вызова сеттера. Идеален для независимых простых значений: флаги, поля ввода, выбранный таб.

useReducer

const reducer = (state, action) => {
  switch (action.type) {
    case 'add':    return { ...state, items: [...state.items, action.item] };
    case 'remove': return { ...state, items: state.items.filter((i) => i.id !== action.id) };
    case 'clear':  return { ...state, items: [] };
    default:       return state;
  }
};

const [state, dispatch] = useReducer(reducer, { items: [] });
dispatch({ type: 'add', item });

Все переходы состояния собраны в одной чистой функции; компоненты лишь сообщают что произошло.

Когда выбирать useReducer

  • Несколько полей меняются согласованно (форма-визард, корзина).
  • Следующее состояние зависит от предыдущего сложным образом.
  • Одни и те же переходы дёргаются из многих мест — логика не дублируется.
  • Нужно тестировать логику отдельно: reducer — чистая функция.
  • dispatch стабилен — его можно передавать вглубь без useCallback.

Когда useState

Всё простое и независимое. Три-четыре несвязанных useState лучше одного «объекта всего» — обновления точнее, код проще.

Нюансы

  • useState внутри реализован через useReducer с базовым редьюсером.
  • useReducer + Context — лёгкий «Redux без Redux» для поддерева.

Коротко для собеседования

useState — прямые сеттеры, логика в обработчиках; для простых независимых значений. useReducer — переходы в одной чистой функции, компоненты диспатчат действия; для сложного взаимосвязанного состояния, тестируемости и стабильного dispatch. Правило: стало сложно согласовывать несколько setX — пора в reducer.

Другие вопросы раздела