最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - ReactJS state not updated In setState callback - Stack Overflow

programmeradmin1浏览0评论

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 ponent is listening to.

The main phone ponent 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?

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 ponent is listening to.

The main phone ponent 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?

Share Improve this question edited Mar 3, 2017 at 16:24 Ryan McClure asked Mar 3, 2017 at 3:11 Ryan McClureRyan McClure 1,2333 gold badges20 silver badges35 bronze badges 8
  • Can you post a full code sample such as where the second code block is being called? – patrick Commented Mar 3, 2017 at 3:51
  • I've added a few more details -- unfortunately it's difficult to give full code samples in this case, as it is a fairly large project. – Ryan McClure Commented Mar 3, 2017 at 4:40
  • Never mind, I misunderstood in a hurry. – Hardik Modha Commented Mar 3, 2017 at 16:50
  • @RyanMcClure Hi..I've created a fiddle based on your example and it's working fine. The only notable difference is that I've used handleUpdate(calls) instead of handleUpdate = ({ calls }). Can you take a look at it? Are those curely braces necessary in parameter?? – Hardik Modha Commented Mar 3, 2017 at 17:11
  • @RyanMcClure Did it solve your issue? – Hardik Modha Commented Mar 3, 2017 at 17:54
 |  Show 3 more ments

3 Answers 3

Reset to default 5

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

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 ponent called <SipProvider/>, which abstracted all JsSIP plexity 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./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 repose may be helpful. It lets you lift the state into a higher-order ponent 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!

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 remend going for ponentDidUpdate.

发布评论

评论列表(0)

  1. 暂无评论