盖茨比:上下文更新导致无限渲染循环

时间:2019-05-13 23:07:17

标签: javascript reactjs gatsby

加载Gatsby页面后,我正尝试更新上下文。

我这样做的方式是,将上下文提供给所有页面,并在页面加载后更新上下文(使用useEffect完成以确保仅在组件安装时发生)。

不幸的是,这会导致无限的渲染循环(也许不是在Firefox中,而是至少在Chrome中)。

为什么会这样?我的意思是,上下文更新意味着将重新渲染提供程序下面的所有组件,但是useEffect应该只运行一次,那就是在组件安装时。

这是代码https://codesandbox.io/s/6l3337447n

当您转到第二页(位于第一页底部的链接)时,就会发生无限循环。

如果我想在每次页面加载时更新上下文,这里的解决方案是什么?

2 个答案:

答案 0 :(得分:1)

默认情况下,useEffect运行每个渲染。在您的示例中,useEffect每次渲染都会更新context,从而触发无限循环。

React doc:

中有此位
  

如果要运行效果并仅将其清理一次(在挂载和卸载时),则可以将空数组([])作为第二个参数传递。这告诉React,您的效果不依赖于道具或状态的任何值,因此它不需要重新运行。这不是特殊情况,它直接取决于依赖项数组始终如何工作。

因此适用于您的示例:

  useEffect(() => {
    console.log("CONTEXT DATA WHEN PAGE 2 LOADS:", data)
    mergeData({
      location,
    })
-  }, [location, mergeData, data])
+  }, [])

这样,useEffect仅在首次安装时运行。我认为您也可以将location留在其中,因为useEffect并不依赖于context的值,因此也可以防止无限循环。

答案 1 :(得分:1)

此问题的正确答案不是将空的依赖项数组传递给useEffect,而是将上下文的mergeData包装在useCallback hook中。我无法编辑您的代码,但您可能还需要像下面的示例一样向您的useCallback添加依赖项

import React, { useState, useCallback } from "react"

const defaultContextValue = {
  data: {
    // set initial data shape here
    menuOpen: false,
  },
  mergeData: () => {},
}

const Context = React.createContext(defaultContextValue)
const { Provider } = Context

function ContextProviderComponent({ children }) {
  const [data, setData] = useState({
    ...defaultContextValue,
    mergeData, // shorthand method name
  })

  const mergeData = useCallback((newData) {
    setData(oldData => ({
      ...oldData,
      data: {
        ...oldData.data,
        ...newData,
      },
    }))
  }, [setData])

  return <Provider value={data}>{children}</Provider>
}

export { Context as default, ContextProviderComponent }

选择的答案是错误的,因为反应文档明确表示不要忽略当前选择的答案所暗示的依赖。

如果您将es-linteslint-plugin-react-hooks一起使用,则会告诉您这是不正确的。

注意

如果使用此优化,请确保数组包含所有值 从组件范围(例如道具和状态)转变过来 时间和效果所使用的时间。否则,您的代码将 参考先前渲染中的陈旧值。进一步了解如何 处理函数以及数组更改过于频繁时的操作。

https://reactjs.org/docs/hooks-effect.html

从依赖关系列表中省略函数是否安全?通常 说不很难记住使用了哪些道具或状态 通过功能以外的效果。这就是为什么通常您想要 在其内部声明一个效果所需的函数。那很容易 查看影响作用的组件范围中的哪些值:

https://reactjs.org/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies