eugene
eugene

Reputation: 41665

react, get updated state after dispatch in functional component

I use selector (don't have to) to retrieve the nextStep

I dispatch someAction and this can change nextStep that I want to do, however the nextStep doesn't get updated with the following code.

const App = (props) => {
  const dispatch = useDispatch()
  const nextStep = useSelector(getNextStep)

  const handleSubmit = () => {
    dispatch(someAction())      // this can change the nextStep
    dispatch(gotoStep(nextStep))   //  this nextStep is computed before someAction
  }

}


export const getNextStep = (state) => {
  let {step, stepList} = state.my_reduxer
  let index = stepList.indexOf(step) // someAction changes stepList
  let next_step = stepList[index + 1]

  return next_step
}

How do I get the updated nextStep for gotoStep action?

-- Edit

I can think of something like the following but not sure if this guarantees the correct behavior

const App = (props) => {
  const dispatch = useDispatch();
  const nextStep = useSelector(getNextStep);
  const [done, setDone] = useState(false);
  const handleSubmit = () => {
    dispatch(someAction()); // this can change the nextStep

    setDone(true);
  };

  useEffect(() => {
    if (done) {
      dipatch(gotoStep(nextStep)); //  nextStep is hopefully updated?
    }
  }, [done]);
};

Upvotes: 5

Views: 4810

Answers (3)

eugene
eugene

Reputation: 41665

Thanks for the discussion @Dennis Vash !

I wasn't sure if your solution would solve the problem I asked in the comment

Here's my solution, I still don't have definitive documented answer, but feel safer with it. (and it seems to work)

const App = (props) => {
  const dispatch = useDispatch();
  const nextStep = useSelector(getNextStep);
  const myStepDone = useSelector(getMyStep);

  const handleSubmit = () => {
    dispatch(someAction()); // this can change the nextStep
    dispatch(updateMyStepDone()); // let's use redux state for done
  };

  useEffect(() => {
    if (myStepDone) {
      dipatch(gotoStep(nextStep)); //  I hope actions I submitted in handleSubmit updates state simulateneously
    }
  }, [myStepDone]);
};

Upvotes: 0

Dennis Vash
Dennis Vash

Reputation: 53874

someAction might change nextStep or it might not change nextStep, and I want to advance to nextStep after done is updated and nextStep is possibly updated.

This code guarantee you advance next step only when done changes and you don't get a staled value.

const App = () => {
  const nextStep = useSelector(getNextStep);
  const stepRef = useRef(nextStep);

  const handleSubmit = () => {
    dispatch(someAction());
    setDone(true);
  };

  useEffect(() => {
    if (done) {
      dispatch(gotoStep(stepRef.current));
    }
  }, [done]);

  useEffect(() => {
    stepRef.current = nextStep;
  }, [nextStep]);
};

Upvotes: 1

Hagai Harari
Hagai Harari

Reputation: 2877

what suppose to trigger your effect is nextStep itself, because if you use done state it's still not guaranteed that object was reduced already

useEffect(() => dipatch(gotoStep(nextStep)), [nextStep]);

in case that at init render you don't want this effect to run then use like follow

const [ isInit, setIsInit ] = useState(true)
useEffect(() => isInit ? setIsInit(false) : dipatch(gotoStep(nextStep)), [nextStep]);

and now your handleSubmit function takes care only for dispatching

const handleSubmit = () => dispatch(someAction()); // this can change the nextStep

Upvotes: 0

Related Questions