箭头函数不通知 redux 状态变化

Posted

技术标签:

【中文标题】箭头函数不通知 redux 状态变化【英文标题】:Arrow function does not notify redux state changes 【发布时间】:2022-01-20 20:59:09 【问题描述】:

我在 react native 中有一个 react 组件,我想手动处理 hardwareBackButton。 当我传递给 hardwareBackPressListener 的 backHandler 函数中的 redux 状态为真或假时,我有不同的行为。

const brandSelected = useSelector(state => state.map.brandSelected);

我的组件中有这个 useSelector 来访问状态。 并且我有 useEffect 函数来监视此状态的变化:(它可以正常工作并在状态更改为 true 或 false 时记录状态。

React.useEffect(() => 
  console.log(brandSelected); // this is false correctly   
, [brandSelected]);

最后我有一个 backHandler 函数,我将它传递给 hardwareBackPress 监听器。

React.useEffect(() => 
  BackHandler.addEventListener('hardwareBackPress', backHandler);
  return () => 
    BackHandler.removeEventListener('hardwareBackPress', backHandler);
  ;
, []);

和backHandler函数:

const backHandler = () => 
  console.log('check, backhandler', brandSelected) // it logs true continuously
  if (brandSelected === true) 
    dispatch(
      dispatchItemToRedux(
        type: CATEGORIES_SELECTION,
        payload: 
          brandSelected: false,
        ,
      ),
    );
    return true;
  
  popScreen(Screens.Map);
  return true;
;

但此函数不会通知brandSelected 状态已更改。它第一次正常工作并调度函数并正确更改 redux 状态并正确使用 useEffect 函数 log false。但在其他尝试中,它无法正常工作并且没有任何改变!

【问题讨论】:

【参考方案1】:

这里的问题是 backHandler 函数中的 brandSelected 陈旧外壳,您在初始渲染周期中传递给 "hardwareBackPress" 事件侦听器。 backHandler 函数只有初始渲染周期中的值,并且永远不会更新/重新封装更新的值。

要解决这个问题,您应该将 backHandler 状态值缓存在一个可以在回调处理程序中引用的 React ref 中。

const brandSelected = useSelector(state => state.map.brandSelected);
const brandSelectedRef = React.useRef(brandSelected);

useEffect(() => 
  brandSelectedRef.current = brandSelected;
, [brandSelected]);

...

const backHandler = () => 
  console.log('check, backhandler', brandSelectedRef.current)
  if (brandSelectedRef.current) 
    dispatch(
      dispatchItemToRedux(
        type: CATEGORIES_SELECTION,
        payload: 
          brandSelected: false,
        ,
      ),
    );
    return true;
  
  popScreen(Screens.Map);
  return true;
;

另一种方法是将backHandler 移入设置事件侦听器的useEffect 挂钩并使用brandSelected 状态作为依赖项,以便更新后的状态值重新包含在回调。

React.useEffect(() => 
  const backHandler = () => 
    console.log('check, backhandler', brandSelected)
    if (brandSelected) 
      dispatch(
        dispatchItemToRedux(
          type: CATEGORIES_SELECTION,
          payload: 
            brandSelected: false,
          ,
        ),
      );
      return true;
    
    popScreen(Screens.Map);
    return true;
  ;

  BackHandler.addEventListener('hardwareBackPress', backHandler);
  return () => 
    BackHandler.removeEventListener('hardwareBackPress', backHandler);
  ;
, [brandSelected]);

【讨论】:

是的,它工作正常。谢谢!但是哪种解决方案对性能更好?如果我在我的组件中反复添加一个监听器并删除它并再次添加,这对我的性能或第一个解决方案有好处吗? 因为我的组件中有不止一个这样的状态 @Mohamadamin 我更喜欢第一个安装和添加事件侦听器的解决方案,一次,并在卸载时删除它们,一次,但这是主观的。就性能而言,删除和添加新侦听器可能会有非常轻微的开销,但我无法想象它会非常明显,除非brandSelected 状态正在更新每个/渲染周期的顺序。两者都应该没问题。

以上是关于箭头函数不通知 redux 状态变化的主要内容,如果未能解决你的问题,请参考以下文章

箭头函数

箭头函数适用场景及需要注意的地方

箭头函数与普通函数的区别 啥是函数

设置状态的新 Promise 接收箭头函数

js 基础 源码学习 柯里化和箭头函数

箭头函数与this