Can I use useReducer from outside component

11,600

React hooks should be called only inside functional components. Hook state is maintained per component instance. If hooks have to be reused, they can be extracted into custom hooks, which are functions that call built-in hooks and are supposed to be called inside functional components:

export const useTotal = () => {
  const [total, totalDis] = useReducer((total, action) => {...}, 0);
  ...
  return [total, totalDis];
};

In case there's a need to maintain common state for multiple components it should be maintained in common parent and be provided to children through props:

const Root = () => (
  const [total, totalDispatcher] = useTotal();

  return <App {...{total, totalDispatcher}}/>
);

const App = props => {
  return (
    <div>{props.total}</div>
  );
};

Or context API:

const TotalContext = createContext();

const Root = () => (
  <TotalContext.Provider value={useTotal()}>
    <App/>
  </TotalContext.Provider>
);

const App = () => {
  const [total] = useContext(TotalContext);
  return (
    <div>{total}</div>
  );
};
Share:
11,600

Related videos on Youtube

punpun
Author by

punpun

Updated on July 14, 2022

Comments

  • punpun
    punpun almost 2 years

    Now I'm trying to use useReducer to created a new way for management state and function but now found the problem is "Hooks can only be called inside of the body of a function component" Is there any way to solve this problem?

    // App Component
    import React from "react";
    
    import { product, productDis } from "./ProductReducer";
    //{product} is state,  {productDis} is dispatch
    
    import { total } from "./TotalReducer";
    //{total} is state and i dont need {totalDis}
    
    
    const App = () => {
      return (
        <div>
          <button onClick={()=>productDis({type:'add',payload:'pen'})}>add</button>
          {product} {total}
        </div>
      );
    };
    export default App;
    
    // ProductReducer Component
    import React, { useReducer } from 'react';
    import {totalDis} from './TotalReducer'
    //{totalDis} is dispatch and i dont need {total}
    
    
    export const [product, productDis] = useReducer((state, action) => {
        switch (action.type) {
            case "add": {
                const product_0 = 'pencil'
                const product_1 = `${action.payload} and ${product_0}`
                totalDis({
                    type:'total_add',
                    payload:'250'
                })
                return product_1;
            }
            default:
                return state;
        }
    }, []);
    
    // TotalReducer Component
    import React, { useReducer } from 'react';
    
    export const [total, totalDis] = useReducer((total, action) => {
        switch (action.type) {
            case "total_add": {
                const vat = action.payload*1.15
                return vat;
            }
            default:
                return total;
        }
    }, 0)
    

    when i click the button on display It should be shown..." pen and pencil 287.5 "

    but it show "Hooks can only be called inside of the body of a function component"

    there any way to solve this problem? or i should back to nature?

  • Artem P
    Artem P over 3 years
    I like how React devs decided that you shouldn't be doing like this and you should do like that. Makes no sense why both ways didn't work.
  • Bryan Grace
    Bryan Grace about 3 years
    That's not an answer to the question.
  • Estus Flask
    Estus Flask about 3 years
    @BryanGrace Can't say about any question, but it definitely answers the question above - whether useReducer can be used inside the component and what are the workarounds. If you didn't understand something, you could ask for a clarification.