useReducer() проти 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- коли логіка керування станом стає «міні-бізнес-логікою».
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.