箭头函数不通知 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 状态变化的主要内容,如果未能解决你的问题,请参考以下文章