当我点击按钮运行rollDice()
时,它没有更新state
。我不知道为什么,因为它在我的控制台日志上正确更新。但state
不是让人耳目一新。
import React from "react"
import Die from "./Die"
export default function App() {
let diceObj = allNewDice()
diceObj = diceObj.map((dice) => ({value: dice, isHeld: false}))
const [dice, setDice] = React.useState(diceObj)
console.log("refreshed")
function allNewDice() {
const newDice = []
for (let i = 0; i < 10; i++) {
newDice.push(Math.ceil(Math.random() * 6))
}
return newDice
}
function rollDice() {
setDice(prevState => {
for (let i = 0; i < prevState.length; i++){
prevState[i].value = Math.ceil(Math.random() * 6)
}
console.log(prevState)
return prevState
})
console.log(dice)
}
const diceElements = dice.map(die => <Die value={die.value} />)
return (
<main>
<div className="dice-container">
{diceElements}
</div>
<button className="roll-dice" onClick={rollDice}>Roll</button>
</main>
)
}
我让它以另一种方式工作,但它困扰着我,因为这似乎也应该工作…
您没有更新!
您不能更新prevState
的值,所以当您在更改后返回prevState
时,您实际上返回相同的prevState
,因此组件不呈现,因为它只在前一个值与新值不同时呈现,这不是情况
一个解是创建一个prevState
的副本,你更新它,然后返回它:
function rollDice() {
setDice(prevState => {
var newValue = [...prevState];
for (let i = 0; i < prevState.length; i++){
newValue[i].value = Math.ceil(Math.random() * 6)
}
return newValue
})
}
for (let i = 0; i < prevState.length; i++){
prevState[i].value = Math.ceil(Math.random() * 6)
}
这段代码改变了之前的状态,但是react希望状态是不可变的。因此,在您返回prevState
之后,react比较新旧状态,看到它们是相同的数组,因此跳过渲染,因为它认为没有任何变化。
修复方法是创建一个新的数组并返回它。例如:
setDice(prevState => {
const nextState = prevState.map(die => {
return {
...die,
value: Math.ceil(Math.random() * 6)
}
});
return nextState;
})
这样做可以清理您的代码:
function rollDice() {
for(let i = 0; i < dice.length; i++) {
const newValue = Math.ceil(Math.random() * 6);
setDice(prevState => [
...prevState.slice(0, i),
{
value: newValue,
isHeld: false,
}
])
}
我还注意到,您可以在allNewDice()函数中创建一个对象,而不需要在顶部执行映射。