简体   繁体   中英

ReactJS state not updated In setState callback

I'm currently building a SIP phone, where the current calls are handled by a SipPhone class, and displayed on the frontend using React. SipPhone has a list of calls which trigger callbacks that a React component is listening to.

The main phone component has an initial state containing an empty Immutable List :

constructor(props) {
    super(props);
    ...
    this.state = {
        calls: List(),
    };
}

This calls list is updated via an event triggered by callbacks whenever the SipPhone updates.

handleUpdate = ({ calls }) => {
    const nextCalls = List(calls.map(call => {
      return new Call({ ... }) // Call is an Immutable Record
    });

    console.log(nextCalls.toJS()); // This prints the new list I want to save
    this.setState({ calls: nextCalls }, () => {
        console.log(this.state.calls.toJS()); // The list is empty here
    });
}

Sometimes it successfully updates the calls list, while at other times calls doesn't change. When I log the list before setting state, it is as it should be, however when logging in the setState callback it remains unchanged from it's previous state. Sometimes it works, sometimes it doesn't.

To further test this, I added a state variable tick which is incremented each time I set the state here. This change is accurately reflected in the callback, while the calls list remains unchanged.

I can't seem to figure out any reason why it would be doing this. I actually began this project using a normal array rather than an immutable list, and encountered the same issue. I've been using React for quite some time now and have never run into this problem...any thoughts?

It turns out another function in my code was setting the state in certain cases right before componentWillUpdate is called, causing it to disregard the initial call to setState. This was the source of error.

We'd faced this issue before , when we used Immutable (and not normal JS)

Digging around, came across this documentation snippet in 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.

Unless using the callback function of setState is really mandated, i'd recommend going for componentDidUpdate .

I personally found JsSIP library quite convoluted because of too many methods and nested callbacks. This is very different to what you normally work with in the React apps. My friend and I once created a simple component called <SipProvider/> , which abstracted all JsSIP complexity away and let us make calls by just configuring props and using context methods. We finally published that package on npm – feel free to benefit from it too!
https://www.npmjs.com/package/react-sip

If you want to store some data in the apps's state but don't want to bother with redux / mobx / apollo client, a library called recompose may be helpful. It lets you lift the state into a higher-order component and thus separate the state logic from its representation. I've been using withState() / withReducer() in a few projects and it's difficult for me to imagine using this.setState() again!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM