You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mapbox GL Draw的draw_create多次触发且捕获旧状态的问题求助

问题原因
  1. 重复绑定事件监听器:每次defineFeature状态更新,useEffect都会重新执行,而你每次执行都给draw.create添加了一个新的事件处理器,但旧的处理器没有被移除。导致绘制完成触发事件时,所有历史绑定的处理器都会被执行。
  2. 闭包捕获旧状态:每个事件处理器都是在对应的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 08:25:19