设置后立即访问 React State
照片由Celso在Unsplash上拍摄
当我浏览 Stack Overflow 问题时,我注意到许多错误都是由于在设置状态值后尝试访问它而导致的。
Stack Overflow 上的一个示例问题。
我曾多次因为没有意识到setState
异步操作而陷入困境。
那么我们如何在设置之后立即访问状态值呢?
😬 问题重现
clickCounts
下面是同步设置状态值后立即访问状态值()的代码。
class App extends Component { | |
state = { clickCounts: {} }; | |
onClick = e => { | |
e.persist(); | |
const clickCounts = { ...this.state.clickCounts }; | |
let clickCount = +clickCounts[e.target.name] || 0; | |
clickCounts[e.target.name] = ++clickCount; | |
this.setState({ clickCounts }; | |
console.log( | |
`Button Name (◀️ outside) = ${e.target.name}`, | |
this.state.clickCounts | |
); | |
}; | |
render() { | |
const buttons = [1, 2, 3].map(id => ( | |
<button | |
key={id} | |
name={`button${id}`} | |
onClick={this.onClick} | |
>{`Button #${id}`}</button> | |
)); | |
return <div className="App">{buttons}</div>; | |
} | |
} |
class App extends Component { | |
state = { clickCounts: {} }; | |
onClick = e => { | |
e.persist(); | |
const clickCounts = { ...this.state.clickCounts }; | |
let clickCount = +clickCounts[e.target.name] || 0; | |
clickCounts[e.target.name] = ++clickCount; | |
this.setState({ clickCounts }; | |
console.log( | |
`Button Name (◀️ outside) = ${e.target.name}`, | |
this.state.clickCounts | |
); | |
}; | |
render() { | |
const buttons = [1, 2, 3].map(id => ( | |
<button | |
key={id} | |
name={`button${id}`} | |
onClick={this.onClick} | |
>{`Button #${id}`}</button> | |
)); | |
return <div className="App">{buttons}</div>; | |
} | |
} |
让我们看看逻辑错误。
console.log
即使在之后进行调用,也无法访问更新的状态值setState
。
😒 解决方法(不推荐)
作为setState
一个操作,您只需等待 React 设置该值即可。
您可能需要等待一段时间才能使用访问更新的状态setTimeout
。
onClick = e => { | |
e.persist(); | |
const clickCounts = { ...this.state.clickCounts }; | |
let clickCount = +clickCounts[e.target.name] || 0; | |
clickCounts[e.target.name] = ++clickCount; | |
this.setState({ clickCounts }; | |
setTimeout(() => { | |
console.log( | |
`Button Name (⏳ setTimeout) = ${e.target.name}`, | |
this.state.clickCounts | |
); | |
}, 100); | |
}; |
onClick = e => { | |
e.persist(); | |
const clickCounts = { ...this.state.clickCounts }; | |
let clickCount = +clickCounts[e.target.name] || 0; | |
clickCounts[e.target.name] = ++clickCount; | |
this.setState({ clickCounts }; | |
setTimeout(() => { | |
console.log( | |
`Button Name (⏳ setTimeout) = ${e.target.name}`, | |
this.state.clickCounts | |
); | |
}, 100); | |
}; |
太棒了🎉。它有效吧?
是的,但是不是,此时,您只是在祈祷🙏)setState
在访问内部状态之前完成setTimeout
。
此外,您还需要持久化事件以便能够访问事件参数,如第 2 行所示(e.persist()
)。
请参阅e.persist 的事件池。
😄 推荐方法
React 官方文档中提到了两种方法。
- 使用传递给的回调
setState
。 - 使用
componentDidUpdate
生命周期方法
让我们来仔细讨论一下这两个问题。
1. 使用传递给setState
setState
具有以下签名。
setState(updater[, callback]) |
setState(updater[, callback]) |
状态使用方法更新后将调用回调,updater
因此回调可以访问更新的内容this.state
。
这是更新的代码和演示。
onClick = e => { | |
e.persist(); | |
const clickCounts = { ...this.state.clickCounts }; | |
let clickCount = +clickCounts[e.target.name] || 0; | |
clickCounts[e.target.name] = ++clickCount; | |
// - From this, | |
// this.setState({ clickCounts }); | |
// + To this | |
this.setState({ clickCounts }, () => | |
console.log( | |
`Button Name (▶️️ inside callback) = `, | |
this.state.clickCounts | |
) | |
); | |
console.log( | |
`Button Name (◀️ outside callback) = ${e.target.name}`, | |
this.state.clickCounts | |
); | |
}; |
onClick = e => { | |
e.persist(); | |
const clickCounts = { ...this.state.clickCounts }; | |
let clickCount = +clickCounts[e.target.name] || 0; | |
clickCounts[e.target.name] = ++clickCount; | |
// - From this, | |
// this.setState({ clickCounts }); | |
// + To this | |
this.setState({ clickCounts }, () => | |
console.log( | |
`Button Name (▶️️ inside callback) = `, | |
this.state.clickCounts | |
) | |
); | |
console.log( | |
`Button Name (◀️ outside callback) = ${e.target.name}`, | |
this.state.clickCounts | |
); | |
}; |
2. 使用componentDidUpdate
生命周期方法
React 文档“通常建议”使用componentDidUpdate
。
我还没能找到原因,但我的猜测是因为componentDidUpdate
可以访问以前的道具和以前的状态(以及在我的演示中在回调之前被调用)。
以下是使用的代码componentDidUpdate
。
componentDidUpdate(prevProps, prevState) { | |
console.log( | |
`this.state.clickCounts(♻️ componentDidUpdate)`, | |
this.state.clickCounts | |
); | |
} |
componentDidUpdate(prevProps, prevState) { | |
console.log( | |
`this.state.clickCounts(♻️ componentDidUpdate)`, | |
this.state.clickCounts | |
); | |
} |
这个演示表明componentDidUpdate
- 可以访问更新的状态值。
- 在setState的回调方法之前调用。
👋 临别赠言
componentDidUpdate
坦白说,我只使用回调来访问更新的值,因为我只是在写这篇博客时才发现推荐的使用方法😝)。
您可以在CodeSandBox上试用该演示。
设置后立即访问 React 状态一文首先出现在Sung 的技术博客上。
鏂囩珷鏉ユ簮锛�https://dev.to/dance2die/accessing-react-state-right-after-setting-it-2kc8