【问题标题】:React useCallback function doesn't get current context valueReact useCallback 函数没有获取当前上下文值
【发布时间】:2021-04-20 15:27:59
【问题描述】:

我正在尝试使用 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]);
}

codesandbox.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}

【问题讨论】:

    标签: reactjs react-hooks react-context


    【解决方案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]);
    
    }
    

    Working codesandbox demo

    【讨论】:

      【解决方案2】:

      我真的找不到我想要的答案,但这里有几件事给你,也许还有其他想写答案的人:

      inside callback {sourceNodeId: null} 告诉我某些事情导致 Context 重置为其初始值,并且您使用 Provider 的方式与我通常看到的非常不典型(尽管更改它似乎并没有真正解决任何问题)。

      我认为useMouseEvents 内部的useContext 可能只是获得默认上下文,但我尝试将事情转移到 guarentee,但情况并非如此,但这似乎不起作用。 (其他人可能想重试此操作?)

      编辑:删除此建议

      与问题无关,但您也想更改您的useEffect

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

      【讨论】:

      • 感谢您的回复。我根据你的建议updatedcodesandbox,但它没有改变任何东西。
      • @Matt 很奇怪,我尝试了很多东西,我只提到了“删除回调”的建议,因为它确实似乎使状态不重置,但现在回到它,是的,什么都没有不同的。就像我说的,I can't really find the answers I was hoping for。稍后我会尝试再看一遍。
      猜你喜欢
      • 2018-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-22
      • 1970-01-01
      • 1970-01-01
      • 2021-06-30
      相关资源
      最近更新 更多