setState doesn't update the state immediately

前端 未结 12 2483
暖寄归人
暖寄归人 2020-11-21 05:25

I would like to ask why my state is not changing when I do an onclick event. I\'ve search a while ago that I need to bind the onclick function in constructor but still the s

相关标签:
12条回答
  • 2020-11-21 05:47

    If you want to track the state is updating or not then the another way of doing the same thing is

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

    This way you can call the method "_stateUpdated" every time you try to update the state for debugging.

    0 讨论(0)
  • 2020-11-21 05:49
     this.setState({
        isMonthFee: !this.state.isMonthFee,
      }, () => {
        console.log(this.state.isMonthFee);
      })
    
    0 讨论(0)
  • 2020-11-21 05:52

    Your state needs some time to mutate, and since console.log(this.state.boardAddModalShow) executes before the state mutates, you get the previous value as output. So you need to write the console in the callback to the setState function

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

    setState is asynchronous. It means you can’t call it on one line and assume the state has changed on the next.

    According to 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.

    Why would they make setState async

    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.

    0 讨论(0)
  • 2020-11-21 05:52

    According to 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.

    Example:

    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);
    
    
    0 讨论(0)
  • 2020-11-21 05:59

    This callback is really messy. Just use async await instead:

    async openAddBoardModal(){
        await this.setState({ boardAddModalShow: true });
        console.log(this.state.boardAddModalShow);
    }
    
    0 讨论(0)
  • 2020-11-21 06:01

    For anyone trying to do this with hooks, you need 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>
      </>
    }
    

    Output:

    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
    
    0 讨论(0)
提交回复
热议问题