繁体   English   中英

React:仅在使用内部组件时在 useEffect 上无限渲染

[英]React: infinite render on useEffect only when using an internal component

我有以下代码ParentDataFilter

父.js

const Parent = () => {
  const [filteredData, setFilteredData] = useState()

  ...

  const Filter = () => {
    return (
      <div>
        <h2>Filter your data</h2>
        <DataFilter data={filteredData} updateFilter={setFilteredData} />
        <Result data={filteredData} />
      </div>
    )
  }


  return (
    <div>
      <h1>Header</h1>
      <Filter />
    </div>
  )
}

数据过滤器.js

const DataFilter = ({ data, updateFilter }) => {
  const [name, setName] = useState(defaultFilters.name)
  const [age, setAge] = useState(defaultFilters.age)
  
    ...(filter logic using data)
  
  useEffect(() => {
    updateFilter({ name, age })
  }, [name, age])
}

在这里,我收到了Maximum update depth exceeded ,也就是无限渲染,我知道为什么。

  1. ParentDataFilter被渲染
  2. DataFilteruseEffect中触发ParentsetFilteredData
  3. 由于setFilteredDataParent级被重新渲染
  4. 正在重新渲染的Parent级触发子组件DataFilter渲染
  5. 从 2 号开始重复

但是,这只是在我将“父”中的Filter提取为内部组件之后才开始发生的......我知道这很奇怪,但是当Parent像这样时它工作正常


const Parent = () => {
  const [filteredData, setFilteredData] = useState()

  ...

  return (
    <div>
      <h1>Header</h1>
        <div>
          <h2>Filter your data</h2>
          <DataFilter data={filteredData} updateFilter={setFilteredData} />
          <Result data={filteredData} />
        </div>
    </div>
  )
}  

有谁知道为什么只有当它作为内部组件时才会发生无限渲染?

我尝试对setFilteredData使用useCallback ,但它没有用。

另外,如果我想将其保留为组件而不是直接将所有内容写入 return(),我应该怎么做才能防止无限渲染?

据我所知,你的推理是正确的。

改写:

子组件触发父组件的setFilteredData

当父组件中的 state 发生更改时,父组件将重新渲染其子组件,这将导致<DataFilter> (以及其他子组件)重新渲染,这会导致 useEffect 再次运行, 因为 useEffect 在每次渲染时运行。

此过程重复,导致父级的 state 更新并再次重新渲染。 这将继续无限循环。

我认为它与您以前的结构一起使用的原因是由于组件的嵌套,父项更改仅更新相关的子项(与您当前设置的更长的嵌套链相反)。

如果你不希望它总是重新渲染,我要么将相关逻辑保留在孩子中,所以孩子只负责自己的 state 并重新渲染,而不是父 state 更改导致孩子重新渲染.

或者,我会考虑将孩子包装在React.memo HOC 中,这将根据道具限制重新渲染。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM