【问题标题】:Arrow function does not notify redux state changes箭头函数不通知 redux 状态变化
【发布时间】: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。但在其他尝试中,它无法正常工作并且没有任何改变!

【问题讨论】:

    标签: reactjs react-native redux react-redux arrow-functions


    【解决方案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 状态正在更新每个/渲染周期的顺序。两者都应该没问题。
    猜你喜欢
    • 1970-01-01
    • 2019-02-01
    • 2023-03-23
    • 2015-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    相关资源
    最近更新 更多