Могу ли я использовать useReducer из внешнего компонента - PullRequest
3 голосов
/ 24 марта 2019

Сейчас я пытаюсь использовать 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"

но это показывает "Крючки могут быть тольковызывается внутри тела компонента функции "

Есть ли способ решить эту проблему?или я должен вернуться к природе?

Ответы [ 2 ]

4 голосов
/ 24 марта 2019

React-хуки должны вызываться только внутри функциональных компонентов. Состояние подключения поддерживается для каждого экземпляра компонента. Если нужно повторно использовать хуки, они могут быть извлечены в пользовательские хуки, которые являются функциями, которые вызывают встроенные хуки и должны вызываться внутри внутренних функциональных компонентов:

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

В случае необходимости поддерживать общее состояние для нескольких компонентов, оно должно поддерживаться в общем родителе и передаваться детям через реквизиты:

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

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

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

Или контекстный API:

const TotalContext = createContext();

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

const App = () => {
  const [total] = useContext(TotalContext);
  return (
    <div>{total}</div>
  );
};
1 голос
/ 24 марта 2019

Из документов ,

Есть три распространенные причины, по которым вы можете видеть это:

  • У вас могут быть несовпадающие версии 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 отправьте действие и внутри метода используйте этот редуктор.

...