SetState 不会立即更新状态

我想问为什么我的状态没有改变,当我做一个 onClick事件。前段时间我曾经搜索过,我需要在构造函数中绑定 onClick函数,但是状态仍然没有更新。

这是我的密码:

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 }); // set boardAddModalShow to true


/* After setting a new state it still returns a false value */
console.log(this.state.boardAddModalShow);
}


render() {
return (
<Col lg={3}>
<a href="javascript:;"
className={style.boardItemAdd}
onClick={this.openAddBoardModal}>
<div className={[style.boardItemContainer,
style.boardItemGray].join(' ')}>
Create New Board
</div>
</a>
</Col>
);
}
}


export default BoardAdd
169884 次浏览

您的状态需要一些时间来变化,而且由于 console.log(this.state.boardAddModalShow)在状态变化之前执行,因此您将获得以前的值作为输出。因此,您需要在对 setState函数的回调中编写控制台

openAddBoardModal() {
this.setState({ boardAddModalShow: true }, function () {
console.log(this.state.boardAddModalShow);
});
}

setState是异步的。这意味着你不能在一行上调用它,然后假设下一行的状态已经改变。

根据 < a href = “ https://facebook.github.io/response/docs/response-Component ent.html # setstate”rel = “ noReferrer”> React docs

setState()不会立即突变 this.state,但会创建一个 调用此命令后访问 this.state 方法可能返回现有值 保证对 setState 的调用的同步操作,并且调用可以 为提高性能而进行批处理。

他们为什么要使 setState异步

这是因为 setState改变了状态并导致重新呈现 可能是一个昂贵的操作,使其同步可能会离开 浏览器没有反应。

因此,setState调用是异步的,也是批处理的 用户界面经验和性能。

幸运的是 setState()接受回调,这就是我们获得更新状态的地方。

考虑一下这个例子。

this.setState({ name: "myname" }, () => {
//callback
console.log(this.state.name) // myname
});

所以当回调触发时,this.state 是更新后的状态。
您可以在回调中获得 mutated/updated数据。

因为 setSatate 是一个异步函数,所以您需要像下面这样将状态控制为一个回调函数。

openAddBoardModal(){
this.setState({ boardAddModalShow: true }, () => {
console.log(this.state.boardAddModalShow)
});
}

如果您想跟踪状态是否更新,那么做同样事情的另一种方法是

_stateUpdated(){
console.log(this.state. boardAddModalShow);
}


openAddBoardModal(){
this.setState(
{boardAddModalShow: true},
this._stateUpdated.bind(this)
);
}

这样,每次尝试更新状态以进行调试时,都可以调用方法“ _ stateUpdated”。

这个回调非常麻烦,只要使用异步等待就可以了:

async openAddBoardModal(){
await this.setState({ boardAddModalShow: true });
console.log(this.state.boardAddModalShow);
}

setState()并不总是立即更新组件。它可以批处理或推迟更新,直到以后。这使得在称 setState()为潜在陷阱之后立即读取 This.state。相反,使用 componentDidUpdatesetState回调函数(setState(updater, callback)) ,这两个函数都保证在应用更新后激发。如果需要根据前面的状态设置状态,请阅读下面的 update 参数。

除非 shouldComponentUpdate()返回 false,否则 setState()将始终导致重新呈现。如果使用了可变对象,并且在 shouldComponentUpdate()中无法实现条件呈现逻辑,那么只有在新状态与前一状态不同时调用 setState()才能避免不必要的重新呈现。

第一个参数是带有签名的 update 函数:

(state, props) => stateChange

state是应用更改时对组件状态的引用。它不应该直接变异。相反,更改应该通过基于状态和道具的输入构建新对象来表示。例如,假设我们希望通过 prop.step 在状态中增加一个值:

this.setState((state, props) => {
return {counter: state.counter + props.step};
});

setState()是异步的。验证状态是否正在更新的最佳方法是在 componentDidUpdate()中,而不是在 this.setState({ boardAddModalShow: true })之后放置 console.log(this.state.boardAddModalShow)

根据 React Docs

可以将 setState ()看作是一个请求,而不是一个用于更新组件的即时命令。为了获得更好的感知性能,React 可能会延迟它,然后在一次通过中更新几个组件。React 不能保证立即应用状态更改

 this.setState({
isMonthFee: !this.state.isMonthFee,
}, () => {
console.log(this.state.isMonthFee);
})

根据 React Docs

React 不能保证立即应用状态更改。 这使得在调用 setState ()之后立即读取 This.state 成为一个潜在的 pitfall,并且由于 async的性质可能返回 existing值。 相反,使用在 setState 操作成功后立即执行的 componentDidUpdatesetState回调。一般来说,我们推荐使用 componentDidUpdate()来代替这种逻辑。

例如:

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 (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={this.updateState}>Update State</button>
</div>
);
}
}


const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);


是的,因为 setState 是一个异步函数。在写入 set state 之后立即设置 state 的最佳方法是像下面这样使用 Object.sign: 例如,你想设置一个属性 isValid 为 true,可以这样做


分配(this. state,{ isValid: true })


您可以在写入此行之后立即访问更新后的状态。

当我运行代码并在控制台检查我的输出时,它显示它是未定义的。 在我四处寻找,找到适合我的东西之后。

componentDidUpdate(){}

在我的代码中,我在构造函数()之后添加了这个方法。 检查反应本机工作流的生命周期。

Https://images.app.goo.gl/bvrai4ea2p4lchqj8

对于任何想用钩子做这件事的人,你需要 useEffect

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 <>
<div> x is {x}. </div>
<button onClick={handleXClick}> set x to 10</button>
<div> y is {y}. </div>
<button onClick={() => setY(20)}> set y to 20</button>
</>
}

产出:

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

现场版

可以将 setState()看作是 请求,而不是立即执行以下命令 更新组件。为了更好地感知性能,反应可能 延迟它,然后一次更新几个组件 不能保证立即应用状态更改。

有关更多信息,请查看 这个

在您的情况下,您已经发送了一个 请求来更新状态。做出反应需要时间。如果您尝试立即 console.log状态,您将获得旧值。

虽然有很多好的答案,但是如果有人在这个页面上寻找 useState的替代品来实现 UI 组件,比如应该根据用户输入打开或关闭的导航抽屉,那么这个答案将会很有帮助。

虽然 useState看起来很方便,但是状态不是立即设置的,因此,你的网站或应用程序看起来滞后... ... 如果你的页面足够大,反应将需要很长时间来计算什么是所有应该更新的状态变化... ..。

我的建议是,当您希望 UI 根据用户操作立即进行更改时,可以使用引用并直接操作 DOM。

为此目的使用状态实际上是一个坏主意,以防反应。

上述解决方案不适用于 useState 挂钩。 可以使用下面的代码

setState((prevState) => {
console.log(boardAddModalShow)
// call functions
// fetch state using prevState and update
return { ...prevState, boardAddModalShow: true }
});