React 不会在状态和道具更改时重新渲染

React is not re-rendering on state and props change

我正在尝试在 React.js 中创建一个非常简单的绘图。实际上,我只是将我创建的 Vanilla JS 代码转换为 React 应用程序。 You can see the original code here on FiddleJS.

似乎一切正常,但渲染点的组件不会在道具更改时重新渲染。然而,它的道具正在改变(我在 react-dev-tools 中检查过)。我正在使用自定义事件侦听器,这可能是错误的原因吗?

import React, { useEffect, useState} from "react";

const addPoint = ({points, setPoints}) => (event) => {
    const newPts = points;
    newPts.push([event.pageX, event.pageY]);
    setPoints(newPts);
};

const handleMouseDown = (pts) => (event) => {
 console.log(pts.points);
  document
    .getElementById("drawing")!
    .addEventListener("mousemove", handleMouseMove(pts));
};

const handleMouseUp = (pts) => (event) => {
  document
    .getElementById("drawing")!
    .removeEventListener("mousemove", handleMouseMove(pts));
};

const handleMouseMove = (pts) => (event) => {
  addPoint(pts) (event);
};

// Does not re-render when the props change
function RenderPoints(props) {
    return (
        <svg id="drawing" height="400" width="450">
        <g id="points" stroke="black" strokeWidth="3" fill="black">
          {props.points.map((point, index) => {
            return <circle cx={point[0]} cy={point[1]} r="3" key={index}/>;
          })}
        </g>
      </svg>
    );
}

export default function Contact() {
  useEffect(() => {
    document
      .getElementById("drawing")!
      .addEventListener("mousedown", handleMouseDown({points, setPoints}));
    document
      .getElementById("drawing")!
      .addEventListener("mouseup", handleMouseUp({points, setPoints}));
    return () => {
      document
        .getElementById("drawing")!
        .removeEventListener("mousedown", handleMouseDown({points, setPoints}));
      document
        .getElementById("drawing")!
        .removeEventListener("mouseup", handleMouseUp({points, setPoints}));
    };
  });
  const [points, setPoints] = useState([[100, 100]]);
  return (
    <>
      <div>Draw</div>
      <RenderPoints points={points} />
    </>
  );
}

addPoints 函数中,您将另一个元素压入同一个 points 数组。 React 在比较数组和对象时会进行浅比较,这意味着它不会深入研究数组内容是否发生了变化——它只是检查状态变量(这里是 points)是对同一个数组的引用还是不同的。

Array.prototype.push 不会创建一个新数组,它只是将一个新元素压入同一个数组。所以即使 points 的内容发生变化, points 仍然是同一个数组。这就是 React 不会重新渲染您的组件的原因。

要解决此问题,请执行以下操作,而不是推入同一个数组:

const newPts = [...points, [event.pageX, event.pageY]]

每次都会创建一个新数组,因此 React 现在会重新渲染您的组件。