1

I'm trying to learn react and in doing so i need to do a lot of console.log(something). In the example below, could you please explain why the second console.log(this.state.foo);, the one within componentDidMount(), is not true? Thanks in advance.

Note: please don't suggest using functional components or hooks, the repo i will be working on is all class based components, so that's what i'm focusing on for now.

class App extends React.Component {
  constructor (props){
    super(props);
    this.state = {
      foo: false
    }
    console.log(this.state.foo);
  }
  
  componentDidMount() {
    console.log('componentDidMount() lifecycle');
    // Trigger update
    this.setState({ foo: true });
    // Why won't this one show in the console?
    console.log(this.state.foo);
  }

  
  render() {
    console.log('Render lifecycle')
    return(
      <h1>Hellos</h1>
  )
    } 
}

ReactDOM.render( < App />, document.getElementById('container'));
Emma Earl Kent
  • 498
  • 5
  • 12
  • 1
    Remember that the console does not log synchronously, so by the time your log _actually_ happens, that state might already have changed. If you want a true snapshot, log `JSON.parse(JSON.stringify(thing))` instead, which _does_ run synchronously and builds a new object. And also remember that `setState` is not synchronous either: it _schedules_ a (possible) state update that won't actually process until the next state update pass. So both these console logs should log "something", just not necessarily the value that you expected them to. – Mike 'Pomax' Kamermans Jul 12 '22 at 22:59
  • Hey - thanks for your comment - the asynchronous part makes sense. However, when i try replacing the console.log(this.state.foo) with JSON.parse(JSON.stringify(foo)) - all within componentDidMount() - I get an error in the console foo is not defined...what am i missing here? – Emma Earl Kent Jul 12 '22 at 23:36
  • you want `console.log(JSON.parse(JSON.stringify(this.state)))`, which now logs your state "as it was when the console log call was scheduled". – Mike 'Pomax' Kamermans Jul 13 '22 at 00:04

2 Answers2

1

That console.log is logging, but it's still logging false for the value this.state.foo. The reason for this is that setState is actually an asynchronous function (in other words, it takes time to execute completely), and you cannot expect the state update operation to have succeeded before you try to access the new value for state.

  componentDidMount() {
    console.log("componentDidMount() lifecycle");
    // Updating state is asynchronous
    this.setState({ foo: true });
    // The line below is running, but the previous line updating state 
    // has not finished executing, which is why it's still logging false
    console.log("component did mount", this.state.foo); 
    // => "component did mount", false
  }

Here are the React docs on the topic.

esinator
  • 76
  • 5
0

As per docs: https://reactjs.org/docs/react-component.html#setstate

setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied.

Your

// Why won't this one show in the console?
console.log(this.state.foo);

Works and shows initial false value, that is actually expected. It will be updated on next shouldComponentUpdate call.

Sergey Sosunov
  • 4,124
  • 2
  • 11
  • 15