setState不会立即更新状态

时间:2016-12-22 08:03:41

标签: javascript reactjs ecmascript-6

我想问一下当我做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

16 个答案:

答案 0 :(得分:100)

您的状态需要一些时间进行变异,并且由于console.log(this.state.boardAddModalShow)在状态变异之前执行,因此您将前一个值作为输出。所以你需要在回调中写入控制台到setState函数

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

}

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

根据 React docs

  

setState()不会立即改变this.state但会创建一个   待定状态转换。在调用此文件后访问this.state   方法可以返回现有值。没有   保证调用setState和调用的同步操作   为获得业绩增长而受到批评。

为什么他们会使setState异步

  

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

     

因此,setState调用是异步的,也是为了更好的批处理   用户体验和性能。

答案 1 :(得分:15)

幸运的是,setState进行了回调。这是我们获取更新状态的地方。考虑这个例子。

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

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

答案 2 :(得分:9)

由于setSatate是异步函数,因此您需要像这样将状态作为回调进行控制台。

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

答案 3 :(得分:4)

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

除非setState()返回false,否则

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

第一个参数是带有签名的更新程序函数

(state, props) => stateChange

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

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

答案 4 :(得分:3)

此回调确实很混乱。只需使用async await代替:

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

答案 5 :(得分:2)

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

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

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

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

答案 6 :(得分:2)

对于尝试使用钩子进行此操作的任何人,您都需要copy body body_clone parse-as-json body 1 parse-as-json body_clone 2 set-column final_result !body_clone_field ? body_field : body_clone_field

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>
  </>
}

答案 7 :(得分:1)

是,因为setState是异步函数。写入设置状态后立即设置状态的最佳方法是使用Object.assign,如下所示: 例如,例如,您要将isValid属性设置为true,请执行以下操作


  

Object.assign(this.state,{isValid:true})


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

答案 8 :(得分:0)

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

根据React Docs

  

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

答案 9 :(得分:0)

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

答案 10 :(得分:0)

根据React Docs

  

反应不能保证状态更改立即生效。   这使得在调用setState()之后立即读取this.state可能是pitfall,并且由于existing的性质,可能会返回async值。   相反,请使用componentDidUpdate或在setState操作成功后立即执行的setState回调。通常,我们建议使用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);

答案 11 :(得分:0)

setState是一个异步函数,因此您可能需要将其用作

this.setState({key:value},()=>{ callYourFunction(this.state.key) });

答案 12 :(得分:0)

当我运行代码并在控制台上检查我的输出时,显示未定义。 在四处搜寻并找到对我有用的东西之后。

componentDidUpdate(){}

我在构造函数()之后的代码中添加了此方法。 看看React Native工作流程的生命周期。

https://images.app.goo.gl/BVRAi4ea2P4LchqJ8

答案 13 :(得分:0)

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

答案 14 :(得分:0)

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

检查this以获得更多信息。

因此,在您的情况下,您已发送请求以更新状态。 React需要一段时间才能做出响应。因此,如果您立即尝试控制状态,则将获得旧值。

答案 15 :(得分:0)

尽管有很多不错的答案,但如果有人在此页面上搜索 _Decimal64 的替代方案以实现应根据用户输入打开或关闭的 UI 组件(如导航抽屉),则此答案会有所帮助。< /p>

虽然 useState 看起来很方便,但状态不会立即设置,因此,您的网站或应用程序看起来很慢...如果您的页面足够大,react 将需要很长时间来计算所有内容应在状态更改时更新...

我的建议是,当您希望 UI 立即更改以响应用户操作时,使用 refs 并直接操作 DOM。

为了这个目的而使用状态对于反应来说真的是一个坏主意。