Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке патерн "Context + Reducer"?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**"Context + Reducer"** - це патерн, який поєднує **Context** (для глобального доступу до даних) і **useReducer** (для передбачуваного керування станом через дії). **Ключове:** Context - це "спосіб поділитися станом", а reducer - "мозок", який каже, *як* стан змінюється.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Суть патерна > Поєднуємо **Context** (для глобального доступу до даних) > і **useReducer** (для передбачуваного керування станом через дії). Context - це "спосіб поділитися станом". Reducer - це "мозок", який каже, *як* стан змінюється. --- ## Базова ідея ```javascript // Context: доступний усім компонентам const CounterContext = createContext(); // Reducer: керує змінами state function counterReducer(state, action) { switch (action.type) { case "increment": return { count: state.count + 1 }; case "decrement": return { count: state.count - 1 }; default: throw new Error("Unknown action"); } } ``` --- ## Реалізація патерна ### 1. Provider (обгортає весь застосунок) ```javascript function CounterProvider({ children }) { const [state, dispatch] = useReducer(counterReducer, { count: 0 }); return ( <CounterContext.Provider value={{ state, dispatch }}> {children} </CounterContext.Provider> ); } ``` --- ### 2. Використання в компонентах ```javascript function CounterDisplay() { const { state } = useContext(CounterContext); return <p>Count: {state.count}</p>; } function CounterButtons() { const { dispatch } = useContext(CounterContext); return ( <> <button onClick={() => dispatch({ type: "decrement" })}>-</button> <button onClick={() => dispatch({ type: "increment" })}>+</button> </> ); } ``` --- ### 3. Обгортаємо застосунок ```javascript function App() { return ( <CounterProvider> <CounterDisplay /> <CounterButtons /> </CounterProvider> ); } ``` --- ## Що відбувається "під капотом" 1. `useReducer` керує локальним станом. 2. `Context.Provider` робить `{ state, dispatch }` доступним глобально. 3. Будь-який компонент у дереві може: - читати поточний стан через `useContext(Context).state`; - змінювати його через `dispatch({ type: "..." })`. --- ## Чому це зручно | Перевага | Опис | |---|---| | Передбачуваність | Усі зміни централізовані через `reducer` | | Глобальна доступність | Через Context стан доступний усьому дереву | | Масштабованість | Можна створювати багато ізольованих "сторів" | | Простота | Не потрібен Redux, Redux Toolkit, Zustand тощо | | Тестованість | `reducer` - чиста функція, легко тестується | | Інкапсуляція | Стан керується строго через `dispatch` | --- ## Просунута версія (розділення state і dispatch) Щоб **уникнути зайвих ререндерів**, контексти часто **розділяють**: ```javascript const StateContext = createContext(); const DispatchContext = createContext(); function CounterProvider({ children }) { const [state, dispatch] = useReducer(counterReducer, { count: 0 }); return ( <DispatchContext.Provider value={dispatch}> <StateContext.Provider value={state}>{children}</StateContext.Provider> </DispatchContext.Provider> ); } // тепер споживачі state і dispatch незалежні: function useCounterState() { return useContext(StateContext); } function useCounterDispatch() { return useContext(DispatchContext); } ``` Тепер зміна `state` не викликає ререндер у компонентів, які підписані лише на `dispatch`. --- ## Де застосовується - Auth: логін/логаут/токен - Theme: темна/світла тема - Cart: кошик в e-commerce - UI: модалки, алерти, лоадери - Form Wizard: переходи між кроками --- ## Підсумок | Що дає | Як реалізується | |---|---| | Глобальний доступ до стану | Context | | Передбачувані оновлення | useReducer | | Централізована логіка | reducer-функції | | Проста архітектура без Redux | поєднання Context + Reducer | --- **Висновок:** > "Context + Reducer" - це міні-Redux, вбудований у React: > простий, чистий, і ідеально підходить для середнього рівня складності застосунку.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.