ReactJS 将 ref 发送到全局 useContext 状态 (Konva)

ReactJS sending ref to global useContext state (Konva)

我正在使用 useContext 作为全局状态解决方案。我有一个包含我的状态的 Store.jsx 和一个减少状态的 reducer.jsx 。我正在使用 Konva 在 HTML5 Canvas 上创建一些形状。我的目标是当我点击一个形状时,我想更新我的全局状态,参考活动的东西,当我再次点击时,清除参考。

我的完整代码可以在这里找到: https://codesandbox.io/s/staging-platform-2li83?file=/src/App.jsx

问题:

问题是当我通过形状的 onClick 事件更新全局状态时,它说引用是 'null',但是当我 console.log onClick 中的引用时我可以看到正确的引用。

我想我遗漏了关于 useRef 工作原理的重要一点。

当我想到这个时,我的脑海中出现了这样的流程:

我创建了一个 canvas,并映射了一个矩形属性数组。这将创建 4 个矩形。我使用 returns 一个矩形的包装器组件。

          {rectArray.map((rectangle, index) => {
            return (
              <RectWrapper key={index} rectangle={rectangle} index={index} />
            );
          })}

在 RectWrapper 内部,我创建了一个引用,将其传递给 Rect 的 ref 属性。在 onclick 函数中,当我控制台日志 'shapeRef' 时,我仅在注释掉 dispatch 时才看到引用。如果我取消注释 dispatch 则它显示为 null,如果我控制台记录状态,则引用始终为 null。

const RectWrapper = ({ rectangle, index }) => {
    const shapeRef = React.useRef();

    return (
      <Rect
        x={rectangle.x + index * 100}
        y={5}
        width={50}
        height={50}
        fill="red"
        ref={shapeRef}
        onClick={() => {
          console.log("ShapeRef: ");
          console.log(shapeRef); // This correctly identifies the rect only when dispatch is uncommented
          dispatch({
            type: "active_image",
            payload: {
              index: index,
              reference: shapeRef
            }
          });
        }}
      />
    );
  };

也许我用钩子来解决这个问题。我只是想保持点击内容的全局状态,因为另一个文件中的组件将依赖于此状态。

出现问题是因为您将 RectWrapper 组件创建为 App 组件中的功能组件,导致一次又一次地创建该组件的新引用,因此引用丢失

将您的 RectWrapper 移动到在 App 组件外部声明的单独组件中,并将 dispatch 作为道具传递给它

import React, { useEffect, useContext, useState, Component } from "react";
import { Stage, Layer, Rect, Transformer } from "react-konva";
import { Context } from "./Store.jsx";
import "./styles.css";

const RectWrapper = ({ rectangle, index, dispatch }) => {
  const shapeRef = React.useRef();

  return (
    <Rect
      x={rectangle.x + index * 100}
      y={5}
      width={50}
      height={50}
      fill="red"
      ref={shapeRef}
      onClick={() => {
        console.log("ShapeRef: ");
        console.log(shapeRef); 
        dispatch({
          type: "active_image",
          payload: {
            index: index,
            reference: shapeRef
          }
        });
      }}
    />
  );
};

export default function App() {
  const [state, dispatch] = useContext(Context);

  console.log("Global State:");
  console.log(state);

  const rectArray = [
    { x: 10, y: 10 },
    { x: 10, y: 10 },
    { x: 10, y: 10 },
    { x: 10, y: 10 }
  ];

  return (
    <div className="App">
      <Stage height={500} width={500}>
        <Layer>
          {rectArray.map((rectangle, index) => {
            return (
              <RectWrapper
                dispatch={dispatch}
                key={index}
                rectangle={rectangle}
                index={index}
              />
            );
          })}
        </Layer>
      </Stage>
    </div>
  );
}

Working demo

我认为您不需要在 RectWrapper 中创建引用,因为 onClick 有一个 event 参数。并且可以在事件中找到被点击的元素的ref:

onClick={(e) => {
    const thisRef = e.target;
    console.log(thisRef );
    ...

这是一个没有 useRef 的工作版本:https://codesandbox.io/s/peaceful-brook-je8qo