最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Can I use useReducer from outside component - Stack Overflow

programmeradmin3浏览0评论

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?

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?

Share Improve this question edited Mar 24, 2019 at 9:35 punpun asked Mar 24, 2019 at 9:27 punpunpunpun 1011 gold badge1 silver badge5 bronze badges 3
  • 3 You can't use useReducer outside of a function component, but you can put the reducer function and initial state outside of it if you prefer, like the example in the documentation. – Tholle Commented Mar 24, 2019 at 9:32
  • thanks but i if I create a new component such as Order component and in the new component i want to access ProductReducer without useContext I can import ProductReducer and it can return state for my new component too – punpun Commented Mar 24, 2019 at 9:49
  • No, you can't do this the way you want. – Estus Flask Commented Mar 24, 2019 at 10:12
Add a comment  | 

3 Answers 3

Reset to default 14

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>
  );
};

With useEnhancedReducer hook introduced here which returns getState function.

You will have something like.

const [state, dispatch, getState] = useEnahancedReducer(reducer, initState)

Because dispatch, getState will never change, they can be used in some hooks without their appearance in the dependence list, they can be stored somewhere else (outside of react) to to be called at anytime, from anywhere.

There is also version of useEnhancedReducer which supports adding middleware, in the same article.

From the docs,

There are three common reasons you might be seeing it:

  • You might have mismatching versions of React and React DOM.
  • You might be breaking the Rules of Hooks.
  • You might have more than one copy of React in the same app.

Deep drive to the docs. I hope, you'll be able to resolve the issue. Especially see:

Breaking the Rules of Hooks:

function Counter() {
  // ✅ Good: top-level in a function component
  const [count, setCount] = useState(0);
  // ...
}

function useWindowWidth() {
  // ✅ Good: top-level in a custom Hook
  const [width, setWidth] = useState(window.innerWidth);
  // ...
}

If you break these rules, you might see this error.

function Bad1() {
  function handleClick() {
    // 
发布评论

评论列表(0)

  1. 暂无评论