错误的React将事件监听器的行为钩住

错误的React将事件监听器的行为钩住,第1张

错误的React将事件监听器的行为钩住

对于使用

useState
挂钩的功能组件,这是常见的问题。相同的问题适用于
useState
使用状态的任何回调函数,例如setTimeout或setInterval定时器函数。

事件处理程序在

CardsProvider
Card
组件中被区别对待。

handleCardClick``handleButtonClick
CardsProvider
功能范围内定义和使用的功能组件。每次运行时都有新功能,它们引用
cards
在定义它们时获得的状态。每次
CardsProvider
呈现组件时都会重新注册事件处理程序。

handleCardClick
用于
Card
功能组件的组件会作为道具接收并在组件支架上一次注册
useEffect
。在整个组件寿命期间,它是相同的功能,并且是指在首次
handleCardClick
定义功能时新鲜的陈旧状态。
handleButtonClick
作为道具接收并在每个
Card
渲染器上重新注册,每次都是新功能,并引用新鲜状态。

可变状态

解决此问题的常用方法是使用

useRef
而不是
useState
。引用基本上是一种配方,提供了一个可变对象,可以通过引用传递该对象:

const ref = useRef(0);function eventListener() {  ref.current++;}

万一组件应该在状态更新时重新渲染(如预期的那样)

useState
,则引用不适用。

可以分别保持状态更新和可变状态,但是

forceUpdate
在类和函数组件中都被视为反模式(列出仅供参考):

const useForceUpdate = () => {  const [, setState] = useState();  return () => setState({});}const ref = useRef(0);const forceUpdate = useForceUpdate();function eventListener() {  ref.current++;  forceUpdate();}
状态更新器功能

一种解决方案是使用状态更新程序功能,该功能从封闭的范围接收新鲜状态而不是陈旧状态:

function eventListener() {  // doesn't matter how often the listener is registered  setState(freshState => freshState + 1);}

如果需要一个状态来实现同步副作用,例如

console.log
,一种解决方法是返回相同状态以防止更新。

function eventListener() {  setState(freshState => {    console.log(freshState);    return freshState;  });}useEffect(() => {  // register eventListener once  return () => {    // unregister eventListener once  };}, []);

这不适用于异步副作用,尤其是

async
函数。

手动事件侦听器重新注册

另一种解决方案是每次都重新注册事件侦听器,因此回调总是从封闭范围获得新状态:

function eventListener() {  console.log(state);}useEffect(() => {  // register eventListener on each state update  return () => {    // unregister eventListener  };}, [state]);
内置事件处理

除非在上注册了事件侦听器

document
window
或者其他事件目标不在当前组件的范围内,否则必须在可能的情况下使用React自己的DOM事件处理,这样就不需要
useEffect

<button onClick={eventListener} />

在最后一种情况下,事件侦听器可以作为道具传递时,还可以通过

useMemo
useCallback
来记住,以防止不必要的重新渲染:

const eventListener = useCallback(() => {  console.log(state);}, [state]);

答案的先前版本建议使用可变状态,该可变状态适用

useState
于React16.7.0-alpha版本中的初始挂钩实现,但不适用于最终的React16.8实现。
useState
当前仅支持不可变状态。



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/4894663.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-12
下一篇 2022-11-12

发表评论

登录后才能评论

评论列表(0条)

保存