关于javascript:setState不会立即更新状态

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


您的状态需要一些时间才能变异,并且由于console.log(this.state.boardAddModalShow)在状态变异之前就已执行,因此您将获得先前的值作为输出。因此,您需要在回调中将控制台写入setState函数

1
2
3
4
5
openAddBoardModal() {
  this.setState({ boardAddModalShow: true }, function () {
    console.log(this.state.boardAddModalShow);
  });
}

setState是异步的。这意味着您不能在一行上调用它,而假定状态在下一行上已更改。

根据React docs

setState() does not immediately mutate this.state but creates a
pending state transition. Accessing this.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.

他们为什么要使setState异步

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.


幸运的是setState()进行了回调。这是我们获取更新状态的地方。

考虑这个例子。

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

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


这个回调真的很混乱。只需使用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)
    });
}

setState()并不总是立即更新组件。它可能会批量更新或将更新推迟到以后。这使得在调用setState()之后立即读取this.state是潜在的陷阱。而是使用componentDidUpdatesetState回调(setState(updater, callback)),可以保证在应用更新后均会触发它们。如果您需要基于先前的状态来设置状态,请阅读下面的updater参数。

除非shouldComponentUpdate()返回false,否则setState()将始终导致重新渲染。如果正在使用可变对象,并且无法在shouldComponentUpdate()中实现条件渲染逻辑,则仅当新状态不同于先前状态时调用setState()可以避免不必要的重新渲染。

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

1
(state, props) => stateChange

state是在应用更改时对组件状态的引用。它不应该直接突变。相反,更改应通过根据状态和道具的输入来构建新对象来表示。例如,假设我们想通过props.step增加状态值:

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"。


对于尝试使用挂钩执行此操作的任何人,您都需要useEffect

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 potential pitfall and can potentially return the existing value due to async nature .
Instead, use componentDidUpdate or a setState callback that is executed right after setState operation is successful.Generally we recommend using componentDidUpdate() 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);

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

根据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);
  })