现在,我正在尝试使用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“
但显示“只能在函数组件的主体内部调用挂钩”
有什么办法可以解决这个问题?还是我应该回归自然?
答案 0 :(得分:3)
仅应在功能组件内部调用反应挂钩。挂钩状态是每个组件实例维护的。如果必须重用钩子,则可以将它们提取到自定义钩子中,这些钩子是调用内置钩子的函数,应该在内部功能组件内部调用:
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 :(得分:1)
从docs,
您可能会看到以下三个常见原因:
深入研究文档。希望您能够解决该问题。特别请参阅:
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(() => {})
// ...
}
}
总而言之,您的错误似乎是在单击处理程序内部使用reducer时出现的。查看示例 Bad1 以解决您的问题。我的意思是,你不应该这样:
onClick={()=>productDis({type:'add',payload:'pen'})}
在onClick处理程序中,分派操作,并在使用该reducer的方法内部。
答案 2 :(得分:0)
在here中引入了app.get( '/', homeController );
钩子,该钩子返回了useEnhancedReducer
函数。
你会有类似的东西。
getState
由于const [state, dispatch, getState] = useEnahancedReducer(reducer, initState)
,dispatch
永远不会改变,因此可以在某些挂钩中使用它们,而不必在依赖列表中出现它们,可以将它们存储在其他地方(在React之外)以在以下位置调用随时随地。
同一篇文章中还提供了getState
版本,该版本支持添加中间件。