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
相关产品推荐
相关产品推荐

