英文:
How to set state in React after a timeout?
问题
在React中,您可以使用setSpinning
来更新spinning
状态,但是在您的代码中,setSpinning(false)
被放置在一个setTimeout
函数内部,这会导致它立即被调用,而不会等待setTimeout
完成。要解决这个问题,您可以将setSpinning(false)
移到setTimeout
函数外部,以确保它在动画完成后再设置spinning
为false
。以下是更改后的代码片段:
const spin = () => {
const num = getRandomNumber();
let numColor = "";
const i = numbers.length * 2 + numbers.indexOf(num) + 1;
for (let j = 0; j < i; j++) {
setTimeout(() => {
setSpinning(true);
if (green.includes(numbers[j % numbers.length])) {
numColor = "green";
} else if (red.includes(numbers[j % numbers.length])) {
numColor = "red";
} else if (black.includes(numbers[j % numbers.length])) {
numColor = "black";
}
document.getElementById("numberDisp").style.color = numColor;
setNumber(numbers[j % numbers.length]);
}, j * (j * 1.25));
}
// 移到这里确保在动画完成后再设置为false
setTimeout(() => {
setSpinning(false);
}, i * (i * 1.25));
};
通过将setSpinning(false)
移动到setTimeout
函数的外部,您可以确保在动画完成后才将spinning
设置为false
。
英文:
I am creating a simple roulette wheel in React and when I attempt to set the state spinning
to false at the end of the function being run it does not change.
import React, { useState } from "react";
const numbers = [
0, 32, 15, 19, 4, 21, 2, 25, 17, 34, 6, 27, 13, 36, 11, 30, 8, 23, 10, 5, 24,
16, 33, 1, 20, 14, 31, 9, 22, 18, 29, 7, 28, 12, 35, 3, 26,
];
const green = [0];
const red = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36];
const black = [
2, 4, 6, 8, 10, 11, 13, 15, 17, 20, 22, 24, 26, 28, 29, 31, 33, 35,
];
const RouletteWheel = () => {
const [number, setNumber] = useState(0);
const [spinning, setSpinning] = useState(false);
const getRandomNumber = () => {
return numbers[Math.floor(Math.random() * numbers.length)];
};
const spin = () => {
const num = getRandomNumber();
let numColor = "";
const i = numbers.length * 2 + numbers.indexOf(num) + 1;
for (let j = 0; j < i; j++) {
setTimeout(() => {
setSpinning(true);
if (green.includes(numbers[j % numbers.length])) {
numColor = "green";
} else if (red.includes(numbers[j % numbers.length])) {
numColor = "red";
} else if (black.includes(numbers[j % numbers.length])) {
numColor = "black";
}
document.getElementById("numberDisp").style.color = numColor;
setNumber(numbers[j % numbers.length]);
}, j * (j * 1.25));
}
setSpinning(false);
};
return (
<div className="roulette">
<h1 id="numberDisp">{number}</h1>
<button onClick={spin} disabled={spinning}>
{spinning ? "Spinning..." : "Spin the wheel!"}
</button>
</div>
);
};
export default RouletteWheel;
I've tried moving around the setSpinning but nothing has fixed it
答案1
得分: 1
I just added useEffect
to your code, added a useEffect hook that listens for changes to the spinning
state and executes any additional code you provide once the state has been updated. I also moved the setSpinning(false)
call inside the loop to ensure that it's executed only once the loop has completed. Calling setSpinning(false)
immediately after the loop will not guarantee that the state has been updated by the time you call it. You can use the useEffect
hook to wait for the state to update before executing additional code.
import React, { useState, useEffect } from "react";
const numbers = [
0, 32, 15, 19, 4, 21, 2, 25, 17, 34, 6, 27, 13, 36, 11, 30, 8, 23, 10, 5, 24,
16, 33, 1, 20, 14, 31, 9, 22, 18, 29, 7, 28, 12, 35, 3, 26,
];
const green = [0];
const red = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36];
const black = [
2, 4, 6, 8, 10, 11, 13, 15, 17, 20, 22, 24, 26, 28, 29, 31, 33, 35,
];
const RouletteWheel = () => {
const [number, setNumber] = useState(0);
const [spinning, setSpinning] = useState(false);
const getRandomNumber = () => {
return numbers[Math.floor(Math.random() * numbers.length)];
};
useEffect(() => {
if (!spinning) {
// additional code to execute once the spinning state has been updated
}
}, [spinning]);
const spin = () => {
const num = getRandomNumber();
let numColor = "";
const i = numbers.length * 2 + numbers.indexOf(num) + 1;
for (let j = 0; j < i; j++) {
setTimeout(() => {
setSpinning(true);
if (green.includes(numbers[j % numbers.length])) {
numColor = "green";
} else if (red.includes(numbers[j % numbers.length])) {
numColor = "red";
} else if (black.includes(numbers[j % numbers.length])) {
numColor = "black";
}
document.getElementById("numberDisp").style.color = numColor;
setNumber(numbers[j % numbers.length]);
if (j === i - 1) {
// last iteration, so set spinning to false
setSpinning(false);
}
}, j * (j * 1.25));
}
};
return (
<div className="roulette">
<h1 id="numberDisp">{number}</h1>
<button onClick={spin} disabled={spinning}>
{spinning ? "Spinning..." : "Spin the wheel!"}
</button>
</div>
);
};
export default RouletteWheel;
英文:
i just added useEffect
to your code, added an useEffect hook that listens for changes to the spinning
state and executes any additional code you provide once the state has been updated. i also moved the setSpinning(false)
call inside the loop to ensure that it's executed only once the loop has completed. Calling setSpinning(false)
immediately after the loop will not guarantee that the state has been updated by the time you call it. You can use the useEffect
hook to wait for the state to update before executing additional code.
import React, { useState, useEffect } from "react";
const numbers = [
0, 32, 15, 19, 4, 21, 2, 25, 17, 34, 6, 27, 13, 36, 11, 30, 8, 23, 10, 5, 24,
16, 33, 1, 20, 14, 31, 9, 22, 18, 29, 7, 28, 12, 35, 3, 26,
];
const green = [0];
const red = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36];
const black = [
2, 4, 6, 8, 10, 11, 13, 15, 17, 20, 22, 24, 26, 28, 29, 31, 33, 35,
];
const RouletteWheel = () => {
const [number, setNumber] = useState(0);
const [spinning, setSpinning] = useState(false);
const getRandomNumber = () => {
return numbers[Math.floor(Math.random() * numbers.length)];
};
useEffect(() => {
if (!spinning) {
// additional code to execute once the spinning state has been updated
}
}, [spinning]);
const spin = () => {
const num = getRandomNumber();
let numColor = "";
const i = numbers.length * 2 + numbers.indexOf(num) + 1;
for (let j = 0; j < i; j++) {
setTimeout(() => {
setSpinning(true);
if (green.includes(numbers[j % numbers.length])) {
numColor = "green";
} else if (red.includes(numbers[j % numbers.length])) {
numColor = "red";
} else if (black.includes(numbers[j % numbers.length])) {
numColor = "black";
}
document.getElementById("numberDisp").style.color = numColor;
setNumber(numbers[j % numbers.length]);
if (j === i - 1) {
// last iteration, so set spinning to false
setSpinning(false);
}
}, j * (j * 1.25));
}
};
return (
<div className="roulette">
<h1 id="numberDisp">{number}</h1>
<button onClick={spin} disabled={spinning}>
{spinning ? "Spinning..." : "Spin the wheel!"}
</button>
</div>
);
};
export default RouletteWheel;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论