是否可以使用 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>
您的问题是这些事件 onHover
和 onClick
每次都会重新初始化,这会导致意外的渲染。如果你的组件有复杂的计算,它会在渲染上滞后。
在你的 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
.
时做错了什么
短篇小说
我想知道这样做是否合适:
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>
您的问题是这些事件 onHover
和 onClick
每次都会重新初始化,这会导致意外的渲染。如果你的组件有复杂的计算,它会在渲染上滞后。
在你的 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
.