web-dev-qa-db-ja.com

外部コンポーネントからuseReducerを使用できますか

今、私はuseReducerを使用して管理状態と機能の新しい方法を作成しようとしていますが、問題は「フックは関数コンポーネントの本体の内部でのみ呼び出すことができます」です。この問題を解決する方法はありますか?

// 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)

ディスプレイ上のボタンをクリックすると表示されます... "ペンと鉛筆287.5"

しかし、「フックは関数コンポーネントの本体の内部でのみ呼び出すことができます」を示しています

この問題を解決する方法はありますか?または私は自然に戻る必要がありますか?

6
punpun

docs から、

あなたがそれを見ているかもしれない3つの一般的な理由があります:

  • ReactとReact DOMのバージョンが一致していない可能性があります。
  • あなたはフックのルールを破っているかもしれません。
  • 同じアプリにReactのコピーが複数ある場合があります。

ドキュメントへの深いドライブ。問題が解決されることを願っています。特に参照してください:

フックのルールを破る:

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

これらのルールに違反すると、このエラーが発生する可能性があります。

function Bad1() {
  function handleClick() {
    // ???? Bad: inside an event handler (to fix, move it outside!)
    const theme = useContext(ThemeContext);
  }
  // ...
}

function Bad2() {
  const style = useMemo(() => {
    // ???? Bad: inside useMemo (to fix, move it outside!)
    const theme = useContext(ThemeContext);
    return createStyle(theme);
  });
  // ...
}

class Bad3 extends React.Component {
  render() {
    // ???? Bad: inside a class component
    useEffect(() => {})
    // ...
  }
}

結論として、エラーはクリックハンドラー内でリデューサーを使用しているように見えます。問題を解決するには、例Bad1を確認してください。ここで私が言っているのは、次のようにしてはいけないことです。

onClick={()=>productDis({type:'add',payload:'pen'})}

OnClickハンドラーでアクションをディスパッチし、メソッド内でそのレデューサーを使用します。

1