setState doesn't update the state immediately
我想问为什么在执行onclick事件时状态没有变化。 我已经搜索了一段时间,我需要在构造函数中绑定onclick函数,但状态仍未更新。 这是我的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | import React from 'react'; import Grid from 'react-bootstrap/lib/Grid'; import Row from 'react-bootstrap/lib/Row'; import Col from 'react-bootstrap/lib/Col'; import BoardAddModal from 'components/board/BoardAddModal.jsx'; import style from 'styles/boarditem.css'; class BoardAdd extends React.Component { constructor(props){ super(props); this.state = { boardAddModalShow: false } this.openAddBoardModal = this.openAddBoardModal.bind(this); } openAddBoardModal(){ this.setState({ boardAddModalShow: true }); // After setting a new state it still return a false value console.log(this.state.boardAddModalShow); } render() { return ( <Col lg={3}> Create New Board </Col> ) } } export default BoardAdd |
您的状态需要一些时间才能变异,并且由于
1 2 3 4 5 | openAddBoardModal() { this.setState({ boardAddModalShow: true }, function () { console.log(this.state.boardAddModalShow); }); } |
根据React docs
setState() does not immediately mutatethis.state but creates a
pending state transition. Accessingthis.state after calling this
method can potentially return the existing value. There is no
guarantee of synchronous operation of calls to setState and calls may
be batched for performance gains.
他们为什么要使
This is because
setState alters the state and causes rerendering. This
can be an expensive operation and making it synchronous might leave
the browser unresponsive.Thus the
setState calls are asynchronous as well as batched for better
UI experience and performance.
幸运的是
考虑这个例子。
1 2 3 4 | this.setState({ name:"myname" }, () => { //callback console.log(this.state.name) // myname }); |
因此,当回调触发时,this.state是更新后的状态。
您可以在回调中获取
这个回调真的很混乱。只需使用async await代替:
1 2 3 4 | async openAddBoardModal(){ await this.setState({ boardAddModalShow: true }); console.log(this.state.boardAddModalShow); } |
由于setSatate是异步函数,因此您需要像这样将状态作为回调进行控制台。
1 2 3 4 5 | openAddBoardModal(){ this.setState({ boardAddModalShow: true }, () => { console.log(this.state.boardAddModalShow) }); } |
除非
第一个参数是带有签名的updater函数:
1 | (state, props) => stateChange |
1 2 3 | this.setState((state, props) => { return {counter: state.counter + props.step}; }); |
如果您想跟踪状态是否正在更新,那么做同一件事的另一种方法是
1 2 3 4 5 6 7 8 9 10 | _stateUpdated(){ console.log(this.state. boardAddModalShow); } openAddBoardModal(){ this.setState( {boardAddModalShow: true}, this._stateUpdated.bind(this) ); } |
这样,您每次尝试更新状态进行调试时都可以调用方法" _stateUpdated"。
对于尝试使用挂钩执行此操作的任何人,您都需要
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | function App() { const [x, setX] = useState(5) const [y, setY] = useState(15) console.log("Element is rendered:", x, y) // setting y does not trigger the effect // the second argument is an array of dependencies useEffect(() => console.log("re-render because x changed:", x), [x]) function handleXClick() { console.log("x before setting:", x) setX(10) console.log("x in *line* after setting:", x) } return <> x is {x}. <button onClick={handleXClick}> set x to 10</button> y is {y}. <button onClick={() => setY(20)}> set y to 20</button> </> } |
输出:
1 2 3 4 5 6 7 8 9 | Element is rendered: 5 15 re-render because x changed: 5 (press x button) x before setting: 5 x in *line* after setting: 5 Element is rendered: 10 15 re-render because x changed: 10 (press y button) Element is rendered: 10 20 |
根据React Docs
React does not guarantee that the state changes are applied immediately.
This makes reading this.state right after calling setState() a potentialpitfall and can potentially return theexisting value due toasync nature .
Instead, usecomponentDidUpdate or asetState callback that is executed right after setState operation is successful.Generally we recommend usingcomponentDidUpdate() for such logic instead.
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | import React from"react"; import ReactDOM from"react-dom"; import"./styles.css"; class App extends React.Component { constructor() { super(); this.state = { counter: 1 }; } componentDidUpdate() { console.log("componentDidUpdate fired"); console.log("STATE", this.state); } updateState = () => { this.setState( (state, props) => { return { counter: state.counter + 1 }; }); }; render() { return ( Hello CodeSandbox Start editing to see some magic happen! <button onClick={this.updateState}>Update State</button> ); } } const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement); |
根据React Docs
Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately
当我运行代码并在控制台上检查我的输出时,它显示未定义。
在我四处寻找并找到对我有用的东西之后。
1 | componentDidUpdate(){} |
我在构造函数()之后的代码中添加了此方法。
查看react native工作流程的生命周期。
https://images.app.goo.gl/BVRAi4ea2P4LchqJ8
是的,因为setState是一个异步函数。写入设置状态后立即设置状态的最佳方法是使用Object.assign,如下所示:
例如,您要将属性isValid设置为true,请按照以下步骤操作
Object.assign(this.state, { isValid: true })
编写此行后,即可访问更新状态。
1 2 3 4 5 | this.setState({ isMonthFee: !this.state.isMonthFee, }, () => { console.log(this.state.isMonthFee); }) |