useReducer() VS useState()
Основна відмінність
| Хук | Для чого |
|---|---|
useState | Простий, незалежний стан (одне значення, коротка логіка) |
useReducer | Складна логіка оновлень, багато взаємопов'язаних даних, зрозуміла структура "дій" (actions) |
Коли варто використовувати useReducer()
1. Коли логіка оновлення складна або багатокрокова
Якщо в тебе кілька типів змін, що залежать від різних умов,
замість безлічі setState та if логічніше мати один централізований reducer.
Приклад:
const [state, dispatch] = useReducer(reducer, { count: 0, step: 1 });
function reducer(state, action) {
switch (action.type) {
case "increment":
return { ...state, count: state.count + state.step };
case "decrement":
return { ...state, count: state.count - state.step };
case "setStep":
return { ...state, step: action.payload };
default:
return state;
}
}Тут useReducer зручніший, ніж три окремих useState.
2. Коли стани взаємопов'язані між собою
Якщо зміна одного поля впливає на інші, useReducer дозволяє
керувати ними в одному місці, а не в десятках setState.
Приклад:
function formReducer(state, action) {
switch (action.type) {
case "CHANGE_FIELD":
return { ...state, [action.field]: action.value };
case "RESET":
return initialForm;
default:
return state;
}
}Керування формою в одному редьюсері - простіше й надійніше, ніж 5 окремих useState.
3. Коли потрібна передбачувана поведінка і "Redux-підхід"
Якщо ти хочеш, щоб оновлення були прозорими, тестованими і централізованими
(наприклад, як у Redux), useReducer робить це вбудованими засобами React.
"Редьюсер робить стан детермінованим: одна й та сама дія -> завжди один і той самий новий стан."
4. Коли оновлення залежать від попереднього стану
Замість написання купи setState(prev => ...),
редьюсер вирішує це за тебе - вся логіка вже всередині reducer().
5. Коли ти хочеш використовувати контекст для глобального стану
Дуже часто useReducer комбінують з useContext, щоб зробити
глобальний стан без Redux / Zustand:
const StoreContext = createContext();
function StoreProvider({ children }) {
const [state, dispatch] = useReducer(reducer, initialState);
return <StoreContext.Provider value={{ state, dispatch }}>{children}</StoreContext.Provider>;
}Це міні-Redux прямо в React - чисто, передбачувано і без зовнішніх залежностей.
Коли НЕ потрібен useReducer
| Випадок | Краще використовувати |
|---|---|
| Простий стан (boolean, число, рядок) | useState |
| Незалежні стани | Декілька useState |
| Логіка коротка й очевидна | useState простіший і читабельніший |
| Немає різних "типів дій" | useReducer надлишковий |
Приклад порівняння
З useState
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
const increment = () => setCount(prev => prev + step);Просто й читабельно - ідеально, якщо логіка проста.
З useReducer
const [state, dispatch] = useReducer(reducer, { count: 0, step: 1 });
function reducer(state, action) {
switch (action.type) {
case "increment":
return { ...state, count: state.count + state.step };
case "setStep":
return { ...state, step: action.payload };
default:
return state;
}
}Зручніше, якщо логіка розширюється - наприклад, з'являться decrement, reset, double тощо.
Підсумок
| Критерій | useState | useReducer |
|---|---|---|
| Проста логіка | так | ні |
| Складні взаємозв'язки | ні | так |
| Багато типів змін | ні | так |
| Централізація логіки | ні | так |
| Легкість написання | так | трохи більше коду |
| Глобальний стан (через контекст) | можливо | ідеально |
Головне правило:
Використовуй
useStateдля простих станів, аuseReducer- коли логіка керування станом стає "міні-бізнес-логікою".
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.