setState不会立即更新状态

Syd*_*ria 72 javascript ecmascript-6 reactjs

我想问一下当我做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 });
// After setting a new state it still return 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
Run Code Online (Sandbox Code Playgroud)

Shu*_*tri 121

你的状态需要一些时间来改变,并且自从console.log(this.state.boardAddModalShow)状态变异之前执行,你得到前一个值作为输出.所以你需要在回调到setState函数的过程中编写控制台

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

}
Run Code Online (Sandbox Code Playgroud)

setState是异步的.这意味着你不能在一行上调用setState并假设状态在下一行已经改变.

根据React docs

setState()不会立即变异this.state但会创建待定状态转换.this.state调用此方法后访问可能会返回现有值.无法保证对setState的调用进行同步操作,并且可以对调用进行批处理以获得性能提升.

为什么他们会使setState异步

这是因为setState改变了状态并导致重新渲染.这可能是一项昂贵的操作,并使其同步可能会使浏览器无响应.

因此,setState调用是异步的,也可以是批处理的,以获得更好的UI体验和性能.

  • @maudev,eslint 规则会阻止你使用 console.logs,这样它们就不会在生产中结束,但上面的例子纯粹是为了调试。和 console.log 并替换为考虑更新状态的操作 (2认同)

Amj*_*d K 23

幸运的是,setState需要回调.这是我们获得更新状态的地方.考虑这个例子.

this.setState(
    { name: "Mustkeom" },
      () => {                        //callback
        console.log(this.state.name) // Mustkeom
      }
);
Run Code Online (Sandbox Code Playgroud)

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


Adn*_*hah 11

由于setSatate是一个异步函数,因此您需要将状态控制为这样的回调.

openAddBoardModal(){
    this.setState({ boardAddModalShow: true }, () => {
        console.log(this.state.boardAddModalShow)
    });
}
Run Code Online (Sandbox Code Playgroud)


Spo*_*ck 9

这个回调真的很混乱。只需使用async await代替:

async openAddBoardModal(){
    await this.setState({ boardAddModalShow: true });
    console.log(this.state.boardAddModalShow);
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以按以下方式管理代码。

openAddBoardModal(){
   this.setState({ boardAddModalShow: true }, () => {
      console.log(this.state.boardAddModalShow);
   });
}
Run Code Online (Sandbox Code Playgroud)

在这里,您可以找到有关ReactJS状态的更多详细信息。

  • @TJCrowder 是对的。`setState` 不会返回承诺,因此不应等待它。也就是说,我想我可以明白为什么这对某些人有用,因为 wait 将 setState 的内部工作放在函数其余部分之前的调用堆栈上,因此它首先被处理,因此看起来状态已经是放。如果 setState 有或实现了任何新的异步调用,则此答案将失败。要正确实现此功能,您可以使用: `await new Promise(resolve =&gt; this.setState({ boardAddModalShow: true }, () =&gt; revok( )))` (23认同)
  • 这是没有意义的。React的setState不返回承诺。 (4认同)

Luk*_*les 7

对于任何试图用钩子来做到这一点的人,你需要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>
  </>
}
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)


小智 5

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

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

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

(state, props) => stateChange
Run Code Online (Sandbox Code Playgroud)

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

this.setState((state, props) => {
    return {counter: state.counter + props.step};
});
Run Code Online (Sandbox Code Playgroud)