React Animated值超过0.8时触发函数 如何规避旧状态监听器残留问题
问题原因
你的useEffect仅在依赖变更时新增监听器,没有移除上一轮渲染生成的旧监听器:
- 每次
DATA_LAYER.names更新都会注册一个新的监听函数,旧监听函数因为闭包特性,绑定的是当时的DATA_LAYER.names快照 - 多个监听器同时触发时,只要有一个旧监听器绑定的names是非空状态,就会触发不符合预期的跳转逻辑
修复方案
给useEffect添加清理逻辑,每次重新注册监听器前,先移除上一轮的旧监听器:
const DATA_LAYER = React.useContext(DataLayerContext); const reactAnimated = React.useRef(new Animated.Value(0)).current; /* Some simple functions to move the reactAnimated value */ const moveNow = () =>{ if (DATA_LAYER.names.length!==0){ props.navigation.navigate("loadingscreen"); } } React.useEffect(()=>{ // 注册监听器,获取监听器唯一ID const listenerId = reactAnimated.addListener(val=>{ if (val.value > .8){ moveNow() // move to next page } }); // 返回清理函数,依赖变更/组件卸载时自动移除当前监听器 return () => { reactAnimated.removeListener(listenerId); } },[DATA_LAYER.names])
可选优化方案(减少监听器重复注册)
如果不需要每次names变更都重新生成监听逻辑,也可以用ref存储最新的names状态,只需要在组件挂载时注册一次监听器即可,避免反复增删监听的性能损耗:
const DATA_LAYER = React.useContext(DataLayerContext); const reactAnimated = React.useRef(new Animated.Value(0)).current; // 用ref同步最新的names状态,避免闭包捕获旧值 const latestNamesRef = React.useRef(DATA_LAYER.names); // 同步更新ref存储的names React.useEffect(()=>{ latestNamesRef.current = DATA_LAYER.names; }, [DATA_LAYER.names]); const moveNow = () =>{ if (latestNamesRef.current.length!==0){ props.navigation.navigate("loadingscreen"); } } // 仅在组件挂载时注册一次监听器 React.useEffect(()=>{ const listenerId = reactAnimated.addListener(val=>{ if (val.value > .8){ moveNow() } }); return () => reactAnimated.removeListener(listenerId); },[])
内容的提问来源于stack exchange,提问作者carlosdafield
相关产品推荐
相关产品推荐

