← Back to React Course | Chapter 9: State Management | Lesson 2 of 10

useReducer और Context को मिलाना

useReducer को Context के साथ combine करना एक official rulebook (reducer) रखने जैसा है जिसे पूरा घर (Context) कोई भी change करने से पहले consult कर सके, हर किसी के अपने rules बनाने के बजाय।
Syntax
markup
const StateContext = createContext();
const DispatchContext = createContext();

function Provider({ children }) {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <StateContext.Provider value={state}>
      <DispatchContext.Provider value={dispatch}>
        {children}
      </DispatchContext.Provider>
    </StateContext.Provider>
  );
}

useReducer को Context के साथ क्यों Combine करें

useReducer state-update logic को एक function में centralize करता है जो हर possible action handle करता है, जो कई separate useState calls से बेहतर scale करता है जब एक app में कई related pieces of state हों।

इसे Context के साथ pair करना state और dispatch function दोनों को tree में कहीं भी available कराता है।

Note: इस combination को अक्सर 'एक mini-Redux' कहा जाता है, क्योंकि reducer + dispatch pattern वही core idea है जिस पर Redux बना है।
Warning: बहुत simple state (एक single toggle या counter) के लिए, plain useState + Context ज़्यादा simple है — useReducer उस state के लिए रखें जिसमें कई related actions हों।

उदाहरण: Why Combine useReducer with Context

markup
<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
  <div id="root"></div>
  <script type="text/babel">
function reducer(state, action) {
  switch (action.type) {
    case "increment": return { count: state.count + 1 };
    case "decrement": return { count: state.count - 1 };
    default: return state;
  }
}
function App() {
  const [state, dispatch] = React.useReducer(reducer, { count: 0 });
  return <button onClick={() => dispatch({ type: "increment" })}>Count: {state.count}</button>;
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
  </script>
</body>
</html>

Context के through State और Dispatch Share करना

एक Provider component एक बार useReducer call करता है और resulting state और dispatch function दोनों को एक Context के through नीचे pass करता है। कोई भी descendant component फिर current state पढ़ सकता है और actions dispatch कर सकता है, उन्हें props के रूप में pass किए बिना।

Note: State और dispatch दोनों को एक object ({ state, dispatch }) के रूप में pass करना Provider के Context.Provider value को tidy रखता है।
Warning: dispatch खुद renders के बीच कभी नहीं बदलता, लेकिन पूरे { state, dispatch } object को Provider में wrap करना अब भी हर render पर एक नया object बनाता है जब तक memoize न किया जाए।

उदाहरण: Sharing State and Dispatch via Context

markup
<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
  <div id="root"></div>
  <script type="text/babel">
const CartContext = React.createContext();
function reducer(state, action) {
  if (action.type === "add") return { items: [...state.items, action.item] };
  return state;
}
function CartProvider({ children }) {
  const [state, dispatch] = React.useReducer(reducer, { items: [] });
  return <CartContext.Provider value={{ state, dispatch }}>{children}</CartContext.Provider>;
}
function AddButton() {
  const { dispatch } = React.useContext(CartContext);
  return <button onClick={() => dispatch({ type: "add", item: "Book" })}>Add Book</button>;
}
function App() {
  return <CartProvider><AddButton /></CartProvider>;
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
  </script>
</body>
</html>

किसी भी Component से Shared State पढ़ना

एक बार reducer और Context wire हो जाने पर, Provider के अंदर nested कोई भी component useContext call करके live state पढ़ सकता है, उस component से पूरी तरह independent जिसने last change trigger किया था।

यही इस pattern को UI के unrelated parts में shared state के लिए useful बनाता है।

Note: useCart() जैसा एक छोटा custom hook बनाएं जो useContext(CartContext) wrap करे, ताकि consumers को raw Context directly import न करना पड़े।
Warning: इस pattern से state पढ़ने वाला एक component हर dispatched action पर अब भी re-render होता है, उन पर भी जो उस part of state को affect नहीं करते जो वह असल में उपयोग करता है।

उदाहरण: Reading Shared State from Any Component

markup
<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
  <div id="root"></div>
  <script type="text/babel">
const CartContext = React.createContext();
function reducer(state, action) {
  if (action.type === "add") return { items: [...state.items, action.item] };
  return state;
}
function CartProvider({ children }) {
  const [state, dispatch] = React.useReducer(reducer, { items: [] });
  return <CartContext.Provider value={{ state, dispatch }}>{children}</CartContext.Provider>;
}
function ItemCount() {
  const { state } = React.useContext(CartContext);
  return <p>Items in cart: {state.items.length}</p>;
}
function App() {
  return <CartProvider><ItemCount /></CartProvider>;
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
  </script>
</body>
</html>
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
आम गलतियां
  1. Actions को उनके type string में typos के साथ dispatch करना, जिन्हें reducer silently ignore कर देता है अगर कोई matching case न हो।
  2. Reducer के switch statement में default case भूल जाना, जो unhandled actions के लिए undefined return कर सकता है।
  3. State और dispatch दोनों को बिना memoize किए एक ही context value में रखना, जो किसी भी change पर हर consumer को re-render कराता है।
चैप्टर सारांश
  • useReducer एक reducer function और dispatched actions के through state manage करता है, Redux के core idea जैसा।
  • इसे Context के साथ combine करना current state और dispatch function दोनों को app-wide share करता है।
  • Components useContext के through state पढ़ते हैं और dispatch({ type: '...' }) call करके changes trigger करते हैं।
  • यह pattern कई related actions वाले state के लिए अच्छी तरह scale करता है, जैसे एक shopping cart या एक multi-field form।
ब्राउज़र सपोर्ट

useReducer के लिए React 16.8 (Hooks introduction) से उपलब्ध है; Context API React 16.3 से stable है।

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.