Mapbox GL Draw的draw_create多次触发且捕获旧状态的问题求助
问题原因
- 重复绑定事件监听器:每次
defineFeature状态更新,useEffect都会重新执行,而你每次执行都给draw.create添加了一个新的事件处理器,但旧的处理器没有被移除。导致绘制完成触发事件时,所有历史绑定的处理器都会被执行。 - 闭包捕获旧状态:每个事件处理器都是在对应的
useEffect执行时创建的闭包,会捕获当时的defineFeature值。所以第一次触发的处理器是组件初始化时绑定的,拿到的是初始null值,后续触发的处理器对应不同状态更新时的绑定,只有最后一次绑定的处理器能拿到最新值。
解决方法
方法一:每次绑定新监听器前移除旧的
在useEffect的清理函数中移除当前绑定的事件处理器,确保同一时间只有一个最新的监听器存在:
useEffect(() => { // 定义当前的事件处理器 const handleDrawCreate = (e) => { // 这里使用的defineFeature就是当前最新值 if (defineFeature) { // 处理路径逻辑 } }; // 绑定监听器 draw.on('create', handleDrawCreate); // 清理函数:组件卸载或依赖更新时移除监听器 return () => { draw.off('create', handleDrawCreate); }; }, [defineFeature]); // 依赖defineFeature,状态更新时重新绑定
方法二:用useRef保存最新状态
通过useRef保存defineFeature的最新值,因为ref的current属性是可变的,不会被闭包捕获旧值,只需绑定一次监听器即可:
import { useRef, useEffect } from 'react'; // 定义ref保存最新状态 const defineFeatureRef = useRef(); // 同步状态到ref useEffect(() => { defineFeatureRef.current = defineFeature; }, [defineFeature]); // 只绑定一次事件监听器 useEffect(() => { const handleDrawCreate = (e) => { // 直接取ref的current,永远是最新值 const latestDefineFeature = defineFeatureRef.current; if (latestDefineFeature) { // 处理路径逻辑 } }; draw.on('create', handleDrawCreate); return () => { draw.off('create', handleDrawCreate); }; }, []); // 这里不需要添加defineFeature作为依赖
方法三:使用useCallback包裹事件处理器(配合方法一)
如果事件处理器逻辑复杂,可以用useCallback缓存它,避免每次useEffect重新创建函数实例,但本质还是要配合清理函数移除旧监听:
import { useCallback, useEffect } from 'react'; const handleDrawCreate = useCallback((e) => { if (defineFeature) { // 处理路径逻辑 } }, [defineFeature]); useEffect(() => { draw.on('create', handleDrawCreate); return () => { draw.off('create', handleDrawCreate); }; }, [handleDrawCreate]);
内容的提问来源于stack exchange,提问作者SpeedGolfer
相关产品推荐
相关产品推荐

