反应功能组件中的异步/等待

Posted

技术标签:

【中文标题】反应功能组件中的异步/等待【英文标题】:async/await in react functional component 【发布时间】:2020-06-30 09:04:55 【问题描述】:

我正在做类似以下的事情

(https://***.com/a/57847874/433570)

 const LowerCard = (props) => 

   let  review_meta, step  = props
   const [component, setComponent] = useState('');
   const state, editDispatch = useContext(ReviewMetaEditCardDispatch);

   useEffect(() => 

     // https://***.com/a/57847874/433570

     const setDynamicComponent = async () => 
       let DynamicComponent
       switch(state.step) 
       case 'title':
         DynamicComponent = await import('review/react/components/review-meta-edit-card/step/title')
         break
       

       if (DynamicComponent) 
         setComponent(DynamicComponent.default)
       
     

     setDynamicComponent()
   , []);


   if (!component) 
     return null
   

   return (
     <View>
       <component/>
     </View>
   )
   

上面的代码有效,但是当我在useEffect 调用中删除[] 时,它会导致 index.js:1 Warning: Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. You can only call Hooks at the top level of your React function.

我猜它在抱怨你不应该在useEffect 中调用setComponent(这是一个钩子)。

我该如何克服这个问题?

【问题讨论】:

哦,那我该如何运行上面的代码来实现等价的componentDidUpdate呢? 我尝试添加 [state.step] 这是导致我更改组件的原因,但它仍然会产生相同的错误 效果里面还有其他条件吗?什么时候重新运行? 【参考方案1】:

你不应该直接在 useEffect 中使用异步函数。

这是我的解决方案,看看它是否有效



const LowerCard = props => 
  let review_meta, step = props;
  const [component, setComponent] = useState('');
  const state, editDispatch = useContext(ReviewMetaEditCardDispatch);

  const setDynamicComponent = useCallback(async () => 
    let DynamicComponent;
    switch (state.step) 
      case 'title':
        DynamicComponent = await import('review/react/components/review-meta-edit-card/step/title');
        break;
    

    if (DynamicComponent) 
      setComponent(DynamicComponent.default);
    
  , [state]);

  useEffect(() => 
    // https://***.com/a/57847874/433570
    setDynamicComponent();
  , [setDynamicComponent]);

  if (!component) 
    return null;
  

  return (
    <View>
      <component />
    </View>
  );
;


【讨论】:

试试component 而不是&lt;component/&gt; JSX中的自定义组件名应该大写【参考方案2】:

您的动态组件正在使用钩子,如果您调用 importedComponent.default,React 将抛出在 useEffect 内部使用钩子的错误错误。

相反,加载组件并在渲染时调用.default

我还添加了 state.stepuseEffect 依赖项数组,以确保在 state.step 发生变化时重新运行效果,就像在初始渲染 state.step 不是 title 组件将永远不会渲染因为您提供了一个空的依赖项数组

useEffect(() => 
  // same as before
  // ...
  if (DynamicComponent) 
    setComponent(DynamicComponent);
  
, [state.step])

if (!component) 
  return null;


return (
  <View>
    <component.default />
  </View>
)

【讨论】:

DynamicComponent.default 不是在调用它,而是在读取参考。在 useEffect 或 render 中附加 .default 没有区别 @Max 实际上确实会有所不同,如果你在 useEffect 中调用 DynamicComponent.default,React 会出错,因为它返回默认导出组件的结果 @Max codesandbox.io/s/peaceful-leaf-wdk6l 删除注释行,看看有什么不同,请务必注释其他行 确实是因为*.default @AsafAviv 我试过你的例子,它确实适用于setComponent(DynamicComponent)。但是我仍然不清楚为什么会发生这种情况,因为这里setComponent(DynamicComponent.default) 我们没有调用函数——调用它是setComponent(DynamicComponent.default())。当我有更多时间时,我会做一些额外的调查

以上是关于反应功能组件中的异步/等待的主要内容,如果未能解决你的问题,请参考以下文章

将异步结果从父组件传递给子组件反应功能组件

在功能性反应组件中获取未定义的道具

从类组件中反应功能组件中的访问值

使用Effect清理功能,防止未挂载的组件异步更新

这是在反应中使用功能组件中的道具时的正确方法

表单作为具有反应的功能组件