如何在另一个组件的状态发生变化后阻止某些react组件重新呈现



我想要渲染x个圆圈。每个圆都在屏幕上的随机位置上渲染。它们中的每一个都有一个value参数,这是将被添加到左上角显示的总点数计数中的数量。单击一个圆圈后,它应该将其值添加到计数中并消失。它做了它应该做的,但是点击时,所有其他圆圈都被重新渲染成一个新的随机位置,这是他们不应该做的。初始设置的x和y位置应该为每个圆生成一次,并保持这样。我该如何防止这种情况发生呢?下面是我的代码:

import { useState } from "react";
import "./App.css";
function App() {
const [count, setCount] = useState(0);
let ctr = 0;
function getRandom(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min) + min);
}
function renderCircle(xPos, yPos, color, value) {
ctr++;
const handleClick = (id) => () => {
setCount(count + value);
const el = document.getElementById(id);
el.style.visibility = "hidden";
};
return (
<div>
{
<svg
className="circle"
id={ctr}
onClick={handleClick(ctr)}
style={{
left: `calc(${xPos}vw - 60px)`,
top: `calc(${yPos}vw - 60px)`,
position: "absolute",
}}
>
<circle cx={30} cy={30} r={30} fill={color} />
</svg>
}
</div>
);
}
function renderCircles(amount) {
const arr = [];
for (let i = 0; i < amount; i++) {
let circle = renderCircle(
getRandom(3, 53),
getRandom(3, 40),
Object.keys(Color)[
Math.floor(Math.random() * Object.keys(Color).length)
],
getRandom(1, 100)
);
arr.push(circle);
}
return arr;
}
return (
<div className="App">
<div className="App-game">{renderCircles(15)}</div>
<div className='App-currency' style={{color: "black", fontSize: 80}}>
{count}
</div>
</div>
);
}
export default App;
class Color {
static Green = new Color("green");
static Blue = new Color("blue");
static Yellow = new Color("yellow");
static Red = new Color("red");
static Pink = new Color("pink");
static Orange = new Color("orange");
constructor(name) {
this.name = name;
}
toString() {
return `Color.${this.name}`;
}
}

您应该将圆圈保存在状态变量

const [circles] = useState(renderCircles(15));
return (
<div className="App">
<div className="App-game">{circles}</div>
<div className="App-currency" style={{ color: 'black', fontSize: 80 }}>
{count}
</div>
</div>
);

您还遇到了svg包装圆圈大小的问题—它要大得多,因此可以在不实际单击圆圈的情况下触发单击事件。你需要将显示设置为none,以防止圆圈再次被点击。

function renderCircle(xPos, yPos, color, value) {
const id = (ctr++).toString();
function handleClick() {
setCount((prev) => prev + value);
const el = document.getElementById(id);
el.style.display = 'none';
}
return (
<svg
className="circle"
id={id}
onClick={handleClick}
style={{
left: `calc(${xPos}vw - 60px)`,
top: `calc(${yPos}vw - 60px)`,
width: 60,
height: 60,
position: 'absolute',
}}
>
<circle cx={'50%'} cy={'50%'} r={'50%'} fill={color} />
</svg>
);
}

Stackblitz: https://stackblitz.com/edit/react-ts-b6jddu?file=App.tsx


注意,当增加计数时,我还将setCount参数更改为回调函数。当新值依赖于前一个值时,您应该养成这样做的习惯。否则你可能会遇到错误。

例如:

const {useState} = React;
function App() {
// count is a local variable, which the value of the state gets copied onto here
const [count, setCount] = useState(0);

function incrementThreeTimesWrong() {
// count is 0 here
setCount(count + 1); // sets to 0 + 1
setCount(count + 1); // sets to 0 + 1
setCount(count + 1); // sets to 0 + 1
// count is still 0 here - setCount does not mutate the local variable
// However setCount triggers a rerender, which will update the local variable to 1
}
function incrementThreeTimesRight() {
setCount(prev => prev + 1); // sets to 0 + 1
setCount(prev => prev + 1); // sets to 1 + 1
setCount(prev => prev + 1); // sets to 2 + 1
}

return (
<div>
<p>{count}</p>
<button onClick={incrementThreeTimesWrong}>Increment three times the wrong way</button>
<br/>
<button onClick={incrementThreeTimesRight}>Increment three times the right way</button>
</div>);
}
ReactDOM.createRoot(
document.getElementById("root")
).render(
<App />
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>

最新更新