5

I want to accomplish the following:

myFunction = () => {
  this.setState(
    state => {
      const originalBar = state.bar;
      return {
        foo: "bar"
      };
    },
    () => ({ originalBar, newBar: state.foo }) //return this object
  );
};

otherFunction = () => {
  var originalValue = myFunction(); //access returned object (in child component)
};

setState doesn't return anything and the only way I could figure how to do this was calling a callback to my function in the setState callback, however, I'd prefer doing this with async await if that's possible.

Tholle
  • 108,070
  • 19
  • 198
  • 189
cubefox
  • 1,251
  • 14
  • 29
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function – Murat Karagöz Mar 12 '19 at 13:33
  • How do you have access to `originalBar` in `setState`'s second parameter? `originalBar` is scoped in just the first callback – Prithwee Das Mar 12 '19 at 13:33
  • 1
    Just a little red flag I picked up - is `otherFunction` in the same component as `myFunction`, or is it in a child component? If it is in a child component, that raises some much bigger red flags about your component design in general, as to why your child component is depending upon your parent component's state update to complete. –  Mar 12 '19 at 13:39
  • @TheThinker my case is pretty specific so I have no other choice here, but why is it a red flag in general? – cubefox Mar 12 '19 at 14:53

3 Answers3

3

You can return a new Promise from myFunction that is resolved in the callback to setState.

Then you can use async/await in your otherFunction.

myFunction = () => {
  return new Promise(resolve => {
    let originalFoo;
    this.setState(
      state => {
        originalFoo = state.foo;
        return {
          foo: "bar"
        };
      },
      () => resolve({ originalFoo, newFoo: this.state.foo })
    );
  });
};

otherFunction = async () => {
  var originalValue = await myFunction();
};
Tholle
  • 108,070
  • 19
  • 198
  • 189
0

My implementation below does not use async/await. If you need to wait until setState is complete, you're probably better off going with Tholle's answer. However, mine is a tad cleaner if you simply want to return an object with values irrespective of whether the state has been fully set.

myFunction = () => {
  let returnData;
  this.setState(state => {
    // do some stuff here
    returnData = { originalBar, newBar: state.foo };
    return {
      foo: "bar"
    };
  });

  return returnData;
}

otherFunction = () => {
  var originalValue = this.myFunction();
}

However, I would not recommend this, and instead I would try not to use a functional callback in this.setState.

Perhaps you could do something like this?

const originalBar = this.state.foo; // or whatever it might be
const newBar = "bar";
this.setState({ foo: newBar });
return { originalBar, newBar };

Quite a bit shorter, and quite a bit more elegant.

  • 1
    This will not work as the function given to `setState` is invoked asynchronously. – Tholle Mar 12 '19 at 13:34
  • @Tholle depends what you mean and what OP wants - if OP simply wants the object, then my code works fine for all intents and purposes. If OP wants the results once `setState` is complete, then I agree that an async method is better. –  Mar 12 '19 at 13:36
0

Looks like you want to acces the previous state and the current state. Rather than using setState to do something that is not intended for it, you can use life cycle methods in react which provide you with the previous state as well as previous props depending upon your usecase.

componentDidUpdate(prevProps, prevState, snapshot){
  ...
}

or

getSnapshotBeforeUpdate(prevProps, prevState){
...
}
Hemant Parashar
  • 3,684
  • 2
  • 16
  • 23
  • Or use the `static getDerivedStateFromProps` [Read more here](https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops) – Jezpoz Mar 12 '19 at 13:39
  • @Jezpoz `getDerivedStateFromProps` doesn't provide a component's prev state. Moreover it's not for this usecase. – Hemant Parashar Mar 12 '19 at 13:41
  • it has to be in the function for my usecase, I'm calling the function from my child component. – cubefox Mar 12 '19 at 13:43