首页 > 解决方案 > 事件监听器反应钩子中的状态更新

问题描述

我创建了简单的自定义挂钩来保存屏幕高度和宽度。问题是我只想重新渲染(更新状态),只有当我的状态中的某些情况发生而不是在每个调整大小事件中。我首先尝试简单的实现:

const useScreenDimensions = () => {
  const [height, setHeight] = useState(window.innerWidth);
  const [width, setWidth] = useState(window.innerHeight);
  const [sizeGroup, setSizeGroup]useState(getSizeGroup(window.innerWidth));

 useEffect(() => {
  const updateDimensions = () => {
   if (getSizeGroup() !== sizeGroup) {
    setSizeGroup(getSizeGroup(width));
    setHeight(window.innerHeight);
    setWidth(window.innerWidth);
  }
};

  window.addEventListener('resize', updateDimensions);
  return () => window.removeEventListener('resize', updateDimensions);
  }, [sizeGroup, width]);

 return { height, width };

}

这种方法的问题是每次都会调用效果,我希望效果只会调用一次而没有依赖项(sizeGroup,width),因为我不想每次屏幕宽度/大小发生变化时都注册事件组(window.addEventListener)。

因此,我尝试使用UseCallBack这种方法,但每次状态发生任何变化时,我的“useEffect”函数都会被调用多次。

//useState same as before..
const updateDimensions = useCallback(() => {
  if (getSizeGroup(window.innerWidth) !== sizeGroup) {
  setSizeGroup(getSizeGroup(width));
  setHeight(window.innerHeight);
  setWidth(window.innerWidth);
}
}, [sizeGroup, width]);

useEffect(() => {
 window.addEventListener('resize', updateDimensions);
 return () => window.removeEventListener('resize', updateDimensions);
}, [updateDimensions]);

....
return { height, width };

问题是我的目的正确有效的方法是什么?我只想“注册”一次事件,并且仅在我的状态变量为真时更新我的​​状态,而不是每次更新宽度或其他内容时更新我的​​状态。

我知道,当您将空数组设置为“UseEffect”的第二个参数时,它只运行一次,但在我的情况下,我希望我的事件侦听器的寄存器运行一次并且在调整大小时我只会在某些条件为真时更新状态

非常感谢。

标签: reactjsreact-hooks

解决方案


使用 2 种不同的 useEffect

第一个用于注册事件。所以下面的代码将在 componentDidMount 时运行。

useEffect(() => {
  window.addEventListener('resize', updateDimensions);
}, []);

第二个 useEffect 根据状态变化运行。

useEffect(() => {
   updateDimensions();
   return () => window.removeEventListener('resize', updateDimensions);
}, [sizeGroup, width])


const updateDimensions = useCallback(() => {
 setSizeGroup(getSizeGroup(width));
 setHeight(window.innerHeight);
 setWidth(window.innerWidth);     
}

我不确定useCallback函数是否需要使用。而且我还没有测试过这段代码。


推荐阅读