提问人:tadain 提问时间:7/18/2022 更新时间:7/18/2022 访问量:629
useState 如何在 react 中与 eventListener 配合使用
How useState works with eventListener in react
问:
在下面的沙盒项目中,我尝试使用自定义钩子来附加事件侦听器。
在 useEventListener.js 文件中,如果我将 savedHandler.current 函数直接传递给事件侦听器(行号:21),则在状态更新期间不会获取更新的状态值。只有当我在匿名函数中使用savedHandler.current函数(行号:19)时,我才会获得更新的状态值。
有人可以帮我了解这是如何工作的吗? 这是因为这个参考吗?
https://codesandbox.io/s/gracious-cloud-kjw7dk?file=/src/useEventListener.js
谢谢
答:
2赞
Dorji Tshering
7/18/2022
#1
这是我能解释的最好的:
对于上下文,当您单击切换标志按钮时,只有您的第一次在每次渲染后运行,而您的第二次在初始渲染后仅运行一次。useEffect(callback,[handler])
useEffect(callback,[eventName,element])
- 现在,当您将 savedHandler.current 直接传递给事件侦听器时,第 21 行,事件侦听器将按原样附加返回的函数,因此在每个事件上,由于以下原因,都会调用相同的函数: 事件仅注册一次,并且清理函数不会运行,因为该函数在初始渲染后仅运行一次(清理函数将在实例中运行, 就在由于依赖项更改而产生的下一个副作用之前,以及当组件卸载时)。因此,您只使用记忆回调注册一次事件,该回调在渲染中持续存在。第一个 savedHandler.current 的更新不会更新第二个中传递给事件侦听器的回调,因为它不会重新运行,因此不会更新传递给事件侦听器的回调。
useCallback
useEffect
useEffect
useEffect
- 现在,当您在匿名函数中使用 savedHandler.current 函数时,这里的场景完全不同。当您将此类函数作为回调传递时,与第一个实例不同,在每个事件上都会调用一个新函数。尽管代码相同,但第一个事件和第二个事件的匿名回调并不相同。因此,在这里,您不会被之前传递的相同事件侦听器回调所困扰,因此您现在可以访问由第一个 useEffect 更新的回调函数中最新的记忆 savedHandler.current 值,尽管第二个效果没有再次运行。
就是这样。为了自己确认,请尝试将 handler 添加为第二个的依赖项,并将 savedHandler.current 直接传递给事件侦听器。您将获得更新的状态值,因为现在在每次更新处理程序后运行,并且事件侦听器会获取要调用的最新回调。
无需创建另一个变量,您可以直接执行useEffect
useEffect
element.addEventListener(eventName, (event) => savedHandler.current(event));
评论
0赞
tadain
7/18/2022
感谢您的详细解释,现在我可以解决这个问题了。我认为既然 ref 基于 reference 工作,那么每次都应该调用更新的函数,即使我们将 ref 直接传递给 eventHandler。只是一个小小的疑问,就像你说的匿名函数在每次事件触发期间都会被 diff 处理,那么 eventListener 将如何被删除?因为我们需要在添加和删除侦听器中传递相同的函数引用。
1赞
Dorji Tshering
7/18/2022
不客气。如果要在添加和删除事件侦听器中传递相同的函数,则可以保持代码不变,在该事件侦听器中,将匿名函数存储在变量中,并将其用作添加和删除侦听器中的引用,这将是相同的,因为它们现在都指向相同的匿名函数。就像一个变量一旦定义就可以多次使用一样,因为它们都指向相同的值,如果更新/更改,所有其他值都指向更新/更改的值并且都相等。
评论
handler
useCallback()
useEffect()