React useCallback 函数未获取当前上下文值

马特

我正在尝试使用带有鼠标事件的 React Hooks 和 React Context API 来实现一个用例。

我想mousemove为容器添加事件。如果用户在对象(矩形)上移动,则调用调度操作并更新上下文值。我想通过在调度之前检查上下文值来实现不重复调度动作。问题是函数没有获得当前的上下文值。

这个事件函数useMouseEvents.js

import * as React from "react";

import { DragToCreateContext, actionTypes } from "./reducer";

export function useMouseEvents(elRef) {
  const { dragToCreate, dispatchDragToCreate } = React.useContext(
    DragToCreateContext
  );

  console.log("out of callback", dragToCreate);

  const handleMouseMove = React.useCallback(
    (evt) => {
      if (evt.target.tagName === "P") {
        console.log("inside callback", dragToCreate);
      }
      if (evt.target.tagName === "P" && dragToCreate.sourceNodeId === null) {
        console.log("dispatch");
        dispatchDragToCreate({
          type: actionTypes.ACTIVATE,
          sourceNodeId: 1
        });
      }
    },
    [dragToCreate]
  );

  React.useEffect(() => {
    const el = elRef?.current;
    if (el) {
      el.addEventListener("mousemove", handleMouseMove);
      return () => {
        el.addEventListener("mousemove", handleMouseMove);
      };
    }
  }, [elRef, handleMouseMove]);
}

代码和盒子.io

如果将鼠标悬停在矩形上,您将在控制台日志中看到:

在此处输入图片说明

inside callback {sourceNodeId: null}
dispatch 
out of callback {sourceNodeId: 1}
inside callback {sourceNodeId: null}
dispatch 
out of callback {sourceNodeId: 1}
inside callback {sourceNodeId: 1}
inside callback {sourceNodeId: null}

但应该是

inside callback {sourceNodeId: null}
dispatch 
out of callback {sourceNodeId: 1}
inside callback {sourceNodeId: 1}
舒巴姆·哈特里

您看到的行为是因为每当您的上下文值更改时,您在 mouseMove 上的侦听器都会被删除和添加。此外,由于您的侦听器是在 useEffect 中重新创建的,因此可能会在附加新侦听器之前执行旧侦听器,并且您从闭包中获得旧值。

为了解决这种情况,您可以使用 ref 来跟踪更新的上下文值并在您的侦听器回调中使用它。这样您就可以避免添加和删除鼠标事件侦听器

import * as React from "react";

import { DragToCreateContext, actionTypes } from "./reducer";

export function useMouseEvents(elRef) {
  const { dragToCreate, dispatchDragToCreate } = React.useContext(
    DragToCreateContext
  );

  console.log("out of callback", dragToCreate);
  const dragToCreateRef = React.useRef(dragToCreate);
  React.useEffect(() => {
    dragToCreateRef.current = dragToCreate;
  }, [dragToCreate]);

  const handleMouseMove = React.useCallback((evt) => {
    if (evt.target.tagName === "P") {
      console.log("inside callback", dragToCreateRef.current);
    }
    if (
      evt.target.tagName === "P" &&
      dragToCreateRef.current.sourceNodeId === null
    ) {
      console.log("dispatch");
      dispatchDragToCreate({
        type: actionTypes.ACTIVATE,
        sourceNodeId: 1
      });
    }
  }, []);

  React.useEffect(() => {
    const el = elRef?.current;
    if (el) {
      el.addEventListener("mousemove", handleMouseMove);
      return () => {
        el.addEventListener("mousemove", handleMouseMove);
      };
    }
  }, [elRef, handleMouseMove]);

}

工作代码和盒子演示

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章