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 现在会重新渲染您的组件。
我正在尝试在 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 现在会重新渲染您的组件。