反应-添加密钥会干扰孩子的状态

时间:2020-03-15 13:36:22

标签: javascript reactjs

有一个需要键的父元素(因为它在创建警告消息的列表中),所以我添加了key = {uuid.v4()}。 这使消息消失了。

有趣的事情开始发生在它的子组件上。当我使用功能性的setState挂钩时,它实际上不再将其分配给该值了(请参见下面的[1])。当我从父组件中删除密钥时,相同的代码可以工作(但留下警告)。 添加静态密钥时,例如key = {'someComponent'},整个组件根本不呈现。 任何提示,我在这里缺少什么?

[1]不更新其状态的子组件:

function zoomIntoRegion(countryName, filter) {
    props.changeFilter({SLMetric: filter})
    if (regionZoom === countryName && filter === props.filter) {
        setRegionZoom(undefined)
    } else {
        console.log('before setzoom', countryName) // # before setzoom GERMANY
        setRegionZoom(countryName)
        console.log('after', regionZoom) // # after undefined
    }
}

1 个答案:

答案 0 :(得分:1)

React中的键用于快速比较当前子项与发生任何更改之前的子项。在渲染功能中将组件上的key设置为uuid.v4()时,每次父组件重新渲染时,您都可以看到它会生成一个新密钥。来自docs

密钥应稳定,可预测且唯一。不稳定的键(如Math.random()产生的键)将导致不必要地重新创建许多组件实例和DOM节点,这可能导致性能下降和子组件中的状态丢失。

这似乎可以准确定义您所面对的事物。

要变通解决此问题,

  1. 如果您根本看不到孩子的顺序发生变化,那么可以使用index作为键。
  2. 如果您确实看到它正在更改并且在可使用的数据中没有密钥,则将密钥生成设置移至您获取/生成数据的位置,以便仅执行一次。确保键在渲染时不改变,而仅在数据本身改变时才改变。
function App() {
  const [items, setItems] = useState([]);
  useEffect(() => {
    getData()
      // mapping over array data and adding the key here
      .then((data) => data.map((item) => ({...item, id: uuid.v4() })))
      .then((data) => setItems(data))
  }, []);
  return (
    <Fragment>
      // using the key
      {items.map((item) => {
        <div key={item.id}>

        </div>
      })}
    </Fragment>
  )
}