事件侦听器反应挂钩中的状态更新

时间:2019-04-28 21:24:51

标签: reactjs react-hooks

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

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 };

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

我知道,当您将空数组设置为'UseEffect'的第二个参数时,它仅运行一次,但就我而言,我希望事件监听器的寄存器运行一次,并在调整大小时仅在某些条件满足时才更新状态是

非常感谢。

1 个答案:

答案 0 :(得分:1)

使用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 函数。而且我还没有测试这段代码。