我们可以根据传递给组件的值动态导入钩子吗?例如App.js
<BaseComponent isActive />
BaseComponent.js
if(props.isActive) { // import useActive (custom Hook) }
我不希望这些(自定义挂钩)文件被导入,并增加基本组件的大小,即使 prop 包含虚假的值。
moiiocjp1#
你可以动态导入钩子,因为它只是一个函数(使用require),但是你不应该因为你不能在条件中使用钩子。参见弯钩规则仅在顶级调用钩子**。不要在循环、条件或嵌套函数内调用钩子。如果你想有条件地使用一个钩子,在它的实现中使用条件(例如,从Apollo GraphQL客户端查看useQuery钩子的skip选项)。
require
useQuery
skip
const useActive = (isUsed) => { if (isUsed) { // logic } }
apeeds0o2#
您应该提取useActive钩子内部的逻辑并动态导入它,而不是动态导入钩子,因为您不应该在循环、条件或嵌套函数内部调用钩子。,checkout Rules of Hooks:假设您的useActive钩子试图更新文档标题(在真实的世界中,它必须是一大块代码,您可以考虑使用动态导入)它可以按如下方式实现:
useActive
// useActive.js import { useEffect } from "react"; export function useActive() { useEffect(() => { document.title = "(Active) Hello World!"; }, []); }
您尝试在BaseComponent中使用它:
BaseComponent
// BaseComponent.js function BaseComponent({ isActive }) { if (isActive) { // <-- call Hooks inside conditions ❌ import("./useActive").then(({ useActive }) => { useActive(); }); } return <p>Base</p>; }
这里您违反了“不要在条件内调用钩子”的规则,并将得到Invalid hook call.错误。因此,您可以提取钩子内部的逻辑并动态导入它,而不是动态导入钩子:
Invalid hook call.
// updateTitle.js export function updateTitle() { document.title = "(Active) Hello World!" }
在钩子内部执行isActive检查:
isActive
// BaseComponent.js function BaseComponent({ isActive }) { useEffect(() => { if (!isActive) return; import("./updateTitle").then(({ updateTitle }) => { updateTitle(); }); }, [isActive]); return <p>Base</p>; }
它工作正常,没有违反任何规则的挂钩。我附加了一个CodeSandbox供您使用:
rsl1atfo3#
无论谁遇到它:您不能在动态导入的组件中使用Hooks(但是,如果您不使用Hooks,即使第一个示例也能正常工作):而不是:
const useDynamicDemoImport = (name) => { const [comp, setComp] = useState(null); useEffect(() => { let resolvedComp = false; import(`@site/src/demos/${name}`) .then((m) => { if (!resolvedComp) { resolvedComp = true; setComp(m.default); } }) .catch(console.error); return () => { resolvedComp = true; }; }, []); return comp; }; const DemoPreviewer: FC<DemoPreviewerProps> = (props) => { comp = useDynamicDemoImport(props.name); return ( <Paper sx={{ position: "relative" }}> {comp} </Paper> ); }; export default DemoPreviewer
请改用ReactLazy,稍后再呈现组件
const useDynamicDemoImport = (name) => { const Comp = React.lazy(() => import(`@site/src/demos/${name}`)); return comp; }; const RootDemoPreviewer: FC<DemoPreviewerProps> = (props) => { console.log("RootDemoPreviewer"); return ( <React.Suspense fallback={<div>Loading...</div>}> <DemoPreviewer {...props} /> </React.Suspense> ); }; const DemoPreviewer: FC<DemoPreviewerProps> = (props) => { const Comp = useDynamicDemoImport(props.name); return ( <Paper sx={{ position: "relative" }}> <Comp /> </Paper> ); }; export default RootDemoPreviewer
b91juud34#
我同意其他人的回答,你不应该这么做。但是如果你必须这么做,你可以创建一个更高级别的组件来获取钩子,然后把它作为一个 prop 传递给一个被 Package 的组件。通过这样做,被 Package 的组件可以在不违反钩子规则的情况下使用钩子,例如从被 Package 组件的Angular 来看,对钩子的引用永远不会改变,并且每次被 Package 的组件呈现时都会被调用。2代码如下所示:
export function withDynamicHook(hookName, importFunc, Component) { return (props) => { const [hook, setHook] = useState(); useEffect(() => { importFunc().then((mod) => setHook(() => mod[hookName])); }, []); if (!hook) { return null; } const newProps = { ...props, [hookName]: hook }; return <Component {...newProps} />; }; } // example of a Component using it: const MyComponent = ({useMyHook}) => { let something = useMyHook(); console.log(something) return <div>myHook returned something, see the console to inspect it </div> } const MyComponentWithHook = withDynamicHook('useMyHook', () => import('module-containing-usemyhook'), MyComponent)
4条答案
按热度按时间moiiocjp1#
你可以动态导入钩子,因为它只是一个函数(使用
require
),但是你不应该因为你不能在条件中使用钩子。参见弯钩规则
仅在顶级调用钩子**。不要在循环、条件或嵌套函数内调用钩子。
如果你想有条件地使用一个钩子,在它的实现中使用条件(例如,从Apollo GraphQL客户端查看
useQuery
钩子的skip
选项)。apeeds0o2#
您应该提取
useActive
钩子内部的逻辑并动态导入它,而不是动态导入钩子,因为您不应该在循环、条件或嵌套函数内部调用钩子。,checkout Rules of Hooks:假设您的
useActive
钩子试图更新文档标题(在真实的世界中,它必须是一大块代码,您可以考虑使用动态导入)它可以按如下方式实现:
您尝试在
BaseComponent
中使用它:这里您违反了“不要在条件内调用钩子”的规则,并将得到
Invalid hook call.
错误。因此,您可以提取钩子内部的逻辑并动态导入它,而不是动态导入钩子:
在钩子内部执行
isActive
检查:它工作正常,没有违反任何规则的挂钩。
我附加了一个CodeSandbox供您使用:
rsl1atfo3#
无论谁遇到它:您不能在动态导入的组件中使用Hooks(但是,如果您不使用Hooks,即使第一个示例也能正常工作):
而不是:
请改用ReactLazy,稍后再呈现组件
b91juud34#
我同意其他人的回答,你不应该这么做。但是如果你必须这么做,你可以创建一个更高级别的组件来获取钩子,然后把它作为一个 prop 传递给一个被 Package 的组件。通过这样做,被 Package 的组件可以在不违反钩子规则的情况下使用钩子,例如从被 Package 组件的Angular 来看,对钩子的引用永远不会改变,并且每次被 Package 的组件呈现时都会被调用。2代码如下所示: