addEventListener与useeffect相撞的火花

const [a, seta] = useState(1)
const [loading, setLoading] = useState(false) //用于等到某个异步操作返回结果后再允许再次触发fn函数

 useEffect(() => {
   document.addEventListener('LazShake.Event.onShakeOnce', () => {
     fn('listener');
   });
 }, []);
 
  useEffect(() => {
    setTimeout(() => {
      seta(2)
    },1000)
  },[])

  const fn = (from) => {
    if (loading) { return }
    setLoading(true);
    const time=new Date(Date.now())
    console.log(11111, 'from: ', from, "min: ",time.getMinutes(),"sec: ",time.getSeconds(), 'a: ',a);
    
    setTimeout(() => {
      setLoading(false)
    }, 2000)
  };

两种方式触发fn, 监听事件:addEventListener; 点击任意事件触发fn:click
发现:监听事件触发的fn,变量a不更新, loading参数不更新, 监听事件的fn为第一次渲染时候的快照,里面的参数后续不更新

addEventListener与useeffect相撞的火花_第1张图片

如果将上述监听事件改为

  const triggerFn = useCallback(() => {
    fn('listener');
  }, [a]);
  
  useEffect(() => {
    document.addEventListener('LazShake.Event.onShakeOnce', triggerFn);
    return () => {
      document.removeEventListener('LazShake.Event.onShakeOnce', triggerFn)
    }
  }, [triggerFn]);

则能保证监听事件触发的fn能拿到最新的变量a
并且每次更新绑定事件的时候,都去先执行回调函数,把之前绑定的triggerFn删除,
关于useeffect中return的执行顺序:在render
![在这里插入图片描述](https://img-blog.csdnimg.cn/58c5de1e30254b91b4a62abba1a8db90.png

addEventListener与useeffect相撞的火花_第2张图片
由于a是在一秒后更新了一次,因此addEventListener函数也只更新了一次,fn里面的loading变量也只更新了一次, 后续loading的更新对fn参数无效, 所以triggerFn依赖变量a还不够,还需要依赖loading变量

你可能感兴趣的:(javascript,开发语言,ecmascript)