【问题标题】:State update in event listener react hooks事件监听器反应钩子中的状态更新
【发布时间】:2019-09-17 13:36:33
【问题描述】:

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

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”的第二个参数时,它只运行一次,但在我的情况下,我希望我的事件侦听器的寄存器运行一次并且在调整大小时,我只会在某些情况下更新状态真的

非常感谢。

【问题讨论】:

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

标签: reactjs react-hooks


【解决方案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 函数是否需要使用。而且我还没有测试过这段代码。

【讨论】:

  • Tnx,我尝试过,但在这种情况下,eslint 插件“强制”我将“updateDimensions”函数设置为对第一个“useEffect”函数的依赖,然后每次发生变化时都会调用它在状态..他想要那个依赖,因为在updateDimensions func中我检查了一些条件是否更新状态(sizegroup-你不检查所以也许在你的情况下eslint不会强迫你将func设置为依赖)
  • 如果你将 [sizeGroup, width] 传递给 useEffect 那么你不需要检查条件。当我需要运行这个函数时,react hooks 会帮你弄清楚。所以不需要 if else 条件。
  • 因此,如果 sizeGroup 和/或宽度仅在那时发生变化,updateDimensions 函数将调用,否则不会调用。
  • setter 有一个函数形式setWidth(oldWidth => newWidth) 能够移除对width 的依赖...
  • 我想我只是放弃了状态下的“组”,并创建了一个函数,该函数通过旧宽度和新宽度计算我的组,如 @Aprillion write ,然后我可以设置新宽度以仅当组是不同的。我看不到另一种方式来思考如何在不依赖组的情况下更新宽度...
猜你喜欢
  • 2019-08-12
  • 2019-12-08
  • 2021-07-13
  • 2021-05-19
  • 1970-01-01
  • 2020-04-19
  • 1970-01-01
  • 1970-01-01
  • 2020-10-27
相关资源
最近更新 更多