是否可以使用 useState hook setter 检索数据以避免重新渲染?

Is it ok to use useState hook setter to retrieve data, to avoid re-renders?

短篇小说

我想知道这样做是否合适:

  const onClick = useCallback(() => {
     setHoveredItem((hovered)=>{
       setSelectedData(hovered);
       return hovered;
     });
  },[]);

只使用useState setter 获取值,'removing' useCallback 的依赖以避免重新渲染。注意空的依赖数组。 这是一种可以接受的做事方式吗?

说来话长

我正在开发一个带有图表的应用程序。重新渲染图表真的很糟糕(它们基本上崩溃了)。所以我用了React.memo。一切都很好,直到我需要传递事件监听器:

<MemoChart
    {...{ data, onHover, onClick }}>
</MemoChart>

单击时,我想存储悬停的项目。

最初,这是我的 onClick 函数:

  const onClick = () => {
    setSelectedData(hoveredItem);
  }

当然,每个悬停事件都会重新呈现父级,这会导致图表重新呈现。在 onClick 上使用回调会起作用,除非我添加对 hoveredItem 的依赖,它什么都不做。

这就是我所做的。它有效,但我从未见过它完成,我想知道是否可以这样做:

  const onClick = useCallback(() => {
     setHoveredItem((hovered)=>{
       setSelectedData(hovered);
       return hovered;
     });
  },[]);

已更新

对于您的情况,我认为您可以使用 useRef 来保留悬停数据而不是状态。

const hoveredRef = React.useRef()

const onHover = useCallback((hovered) => {
   hoveredRef.current = hovered //won't make re-rendering
}, [])

const onClick = useCallback(() => {
   setSelectedData(hoveredRef.current)
}, [])

旧答案

<MemoChart
    {...{ data, onHover, onClick }}>
</MemoChart>

您的问题是这些事件 onHoveronClick 每次都会重新初始化,这会导致意外的渲染。如果你的组件有复杂的计算,它会在渲染上滞后。

在你的 onClick 案例 useCallback 中,它可以工作,但它会在状态处理程序中造成更多麻烦,因为它缺乏依赖性,这意味着它正在考虑函数将始终相同,但是事实上,您的功能依赖于 hovered 状态应根据事件更改。

我建议您传递依赖项以与您在函数中使用的状态保持一致。

const onHover = useCallback((hovered) => {
   setHoveredItem(hovered);
}, []) //only initialize this function once after the component mounted

const onClick = useCallback(() => {
     setSelectedData(hovered);
},[hovered]); //initialize this function again when `hovered` state changes
const onClick = useCallback(() => {
     setHoveredItem((hovered)=>{
       setSelectedData(hovered);
       return hovered;
     });
  },[]);

这没有错,但它是一种 hack,可以帮助您在遇到关闭问题时获得最新状态。 在你的情况下没有理由因为你没有使用闭包,问题只是你设置了一个空的 deps 数组。 现在你说这不行:

const onClick = useCallback(() => {
       setSelectedData(hovered);
  },[hovered]);

但是这个 必须 工作,除非你在调用 setHovereditem.

时做错了什么