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

react-dnd的useDrop钩子drop方法始终读取初始state而非更新后状态问题

问题原因

这是典型的React闭包陷阱问题。你传入useDrop的配置函数在组件首次渲染时执行,捕获了当时作用域下的test值(初始为false)。默认情况下useDrop不会随组件重渲染更新内部配置,所以drop方法永远读取的是首次渲染时捕获的旧值,哪怕后续state更新也不会变化。

解决方案

有两种常用的修复方案:

方案1:给useDrop添加依赖数组

和useEffect逻辑一致,将配置中用到的外部变量test加入useDrop的第二个参数依赖数组中,test变化时useDrop会自动重新生成最新的配置,内部函数就能捕获到最新的state值:

export const Dustbin = () => {
  const [test, setTest] = useState(false);
  const [{ canDrop, isOver }, drop] = useDrop(() => ({
    accept: ItemTypes.BOX,
    hover: () => {
      setTest(true);
    },
    drop: () => {
      console.log(test, "drop"); // 此时可正常读取到最新的test值
      return { name: "Dustbin" };
    },
    collect: (monitor) => ({
      isOver: monitor.isOver(),
      canDrop: monitor.canDrop()
    })
  }), [test]); // 新增:将test加入依赖数组
  const isActive = canDrop && isOver;
  let backgroundColor = "#222";
  if (isActive) {
    backgroundColor = "darkgreen";
  } else if (canDrop) {
    backgroundColor = "darkkhaki";
  }
  console.log(test, "render");
  return (
    <div ref={drop} role={"Dustbin"} style={{ ...style, backgroundColor }}>
      {isActive ? "Release to drop" : "Drag a box here"}
    </div>
  );
};

该方案适合依赖项较少、变化不频繁的场景。

方案2:用useRef同步state值

useRef的current属性是可变引用,不受闭包限制。你可以用ref同步state的值,drop时直接读取ref的current就能拿到最新值,不需要更新useDrop的配置:

export const Dustbin = () => {
  const [test, setTest] = useState(false);
  // 定义ref同步state
  const testRef = useRef(test);
  // state变化时更新ref的值
  useEffect(() => {
    testRef.current = test;
  }, [test])

  const [{ canDrop, isOver }, drop] = useDrop(() => ({
    accept: ItemTypes.BOX,
    hover: () => {
      setTest(true);
    },
    drop: () => {
      console.log(testRef.current, "drop"); // 读取ref拿到最新值
      return { name: "Dustbin" };
    },
    collect: (monitor) => ({
      isOver: monitor.isOver(),
      canDrop: monitor.canDrop()
    })
  }));
  const isActive = canDrop && isOver;
  let backgroundColor = "#222";
  if (isActive) {
    backgroundColor = "darkgreen";
  } else if (canDrop) {
    backgroundColor = "darkkhaki";
  }
  console.log(test, "render");
  return (
    <div ref={drop} role={"Dustbin"} style={{ ...style, backgroundColor }}>
      {isActive ? "Release to drop" : "Drag a box here"}
    </div>
  );
};

该方案适合依赖项较多、state变化频繁的场景,性能更优。

内容的提问来源于stack exchange,提问作者shiva shukla

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 06:48:00