如何避免在每次渲染时触发useEffect?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何避免在每次渲染时触发useEffect?相关的知识,希望对你有一定的参考价值。

我正在创建一个自定义钩子,它接受一个对象,然后调用useEffect。该对象可以包含内联函数。

const stuff = useValidation(
  fields: 
    username:  /* more nested objects */ 
  ,
  onSubmit: () => alert('submitted'),
);

钩子实现看起来像这样:

function useValidation(config) 
  const [state, dispatch] = useReducer(validationReducer);
  useEffect(() => 
    validateFields(config.fields, state);
  , [config.fields, state]);

还有更多(here's the actual implementation),但这些是相关的部分。

当我内联创建对象时,useEffect连续运行。发生这种情况是因为React使用引用相等(不是深度相等)来检查内容是否已更改。

我可以通过在useMemo中包装我的配置来“修复”这个,或者将它移到render方法之外。这两者对开发人员的体验都非常糟糕。

我尝试了Kent C. Dodds的use-deep-compare-effect库,但由于我在配置中允许使用内联箭头功能,因此它不起作用。

我希望能够让用户输入内联对象,让我以某种方式处理任何更改。

我怎么解决这个问题?

答案

在我看来,每次渲染都会调用useEffect,因为传递给useValidation的配置每次都是动态创建的。我的建议是把它放在你使用useValidation的组件或useValidation本身的某个地方,如下所示:

function useValidation(config) 
  const [storedConfig, setStoredConfig] = useState(config);
  const [state, dispatch] = useReducer(validationReducer);

  useEffect(() => 
    validateFields(config.fields, state);
  , [storedConfig.fields, state]);

如果配置是可更改的,那么你应该将它存储在钩子之外,无论哪种方式确保配置不是每个渲染的新对象。

另一答案

看起来它只是代码中的语法错误。

你的功能应该是这样的

function useValidation(config) 
 const [state, dispatch] = useReducer(validationReducer);
  useEffect(() => 
    validateFields(config.fields, state);
  , [config.fields, state])

以上是关于如何避免在每次渲染时触发useEffect?的主要内容,如果未能解决你的问题,请参考以下文章

渲染组件时不触发 useEffect

停止在挂载上运行 useEffect

为啥每次渲染都会调用 `useEffect` 的清理功能?

如何在 useEffect Hook 中重新渲染组件

如何使用 react-hooks (useEffect) 缓冲流数据以便能够一次更新另一个组件以避免多次重新渲染?

useEffect 钩子完成后如何渲染组件?