2

I have simple component

class App extends Component {
    handleClick() {
        let banana = {message: 'banana triggered'};
        this.setState({banana});

        console.log(this); // banana is set in state!!!!
        console.log(this.state); // state is null :O
        setTimeout(() => {
            console.log(this.state); // banana is set!
        }, 5)
    }

    render() {
        const {state, actions} = this.props;

        return (
                <div>
                    {this.state && this.state.banana.message} <br />
                    <button onClick={() => this.handleClick()}>Test</button>


                    {state.alert.message && <p>{state.alert.message}</p>}
                    <p onClick={() => actions.alert.success("This is not")}>
                        This is magic
                    </p>
                </div>
        )
    };
}

export default connect(
    state => (
        {
            state: {...state}
        }
    ),
    dispatch => (
        {
            actions: {
                dispatch: dispatch,
                alert: {
                    success: text => dispatch(alert.success(text))
                }
            }
        }
    )
)(App);

problem is what i need to add this.state && in my JSX rendering to check if this.state exists at all, i understand what in JavaScript it's normal, but is not normal in React.js? Should he react to state change instantly? Also what get me confused, is what from two console.logs, first (this) have banana set in state, and second one is empty. How?

Image below:

enter image description here

p.s. there is no such problem with Redux, only local component state

Mayank Shukla
  • 100,735
  • 18
  • 158
  • 142
Itsmeromka
  • 3,621
  • 9
  • 46
  • 79
  • 1
    setState is async. we cant except value to be present in state in same life cycle hook – G_S Mar 05 '18 at 08:27
  • the reason you get 2 different values on console is because when you open the `this` object, it shows the current values. Do you see a small icon at the end of line ? Hover over it to see. The reason could be that the state is not set during both your `console.log`s but by the time you open the object, it's set already – Dane Mar 05 '18 at 08:34
  • problem is not two different values, problem is when you output whole object, key is set, then immediately after you output this key, from this object, key is null. – Itsmeromka Mar 05 '18 at 08:36

2 Answers2

2

react's docs mention that state updates are asynchronous. In order to act based on the change of the state, react setState function provides a callback which you can use as follows:

this.setState({banana}, () => {
    console.log(this.state);
});

In regards to your comment, the value of the state didn't actually exist when it was printed. the value was calculated only after you clicked the expand arrow in the console see this for more deatils

Yoav
  • 3,326
  • 3
  • 32
  • 73
  • Roger that, this answers why state is null in render, but why despite banana key is already in state object, it outputs null in second console.log in `handleClick` ? p.s. I ll accept your answer a bit later, because if i ll do it now, everybody will skip this question :) – Itsmeromka Mar 05 '18 at 08:37
1

According to react docs, setState() is asynchronous, and multiple calls during the same cycle may be batched together. If you check the updated state value, you can add a callback method

this.setState({ banana }, ()=> {
 // console.log(this.state);
 // Here's the updated state
});

In your case, the first console.log(this) doesn't set the banana. See your code in Sandbox. It looks like first two console logs don't show any state as the initial state is null and after the timeout when the asynchronous call has finished it set the state with banana.

fyasir
  • 2,924
  • 2
  • 23
  • 36