OhkaBaka
OhkaBaka

Reputation: 349

How do I nest async React hooks

This is a massively simplified version a React Hook solution that I am stuck on...

export const useStepA = () => {
  const [stepA, setStepA] = useState();
  const getStepA = useCallback(async (stepAParam: string) => {
    setStepA({ stepBId: '1' });
  }, []);
  return { getStepA, stepA };
};
export const useStepB = () => {
  const [stepB, setStepB] = useState();
  const getStepB = useCallback(async (stepBParam: string) => {
    setStepB(stepBParam);
  }, []);
  return { getStepB, stepB };
};
export const useStepC = () => {
  const { getStepA, stepA } = useStepA();
  const { getStepB, stepB } = useStepB();
  const [stepC, setStepC] = useState();
  const getStepC = useCallback(
    async (stepAParam: string) => {
      /* ????? await? useEffect? magic?
      getStepA(stepAParam);
      getStepB(stepA.stepBId);
      */
      setStepC({stepA,stebB});
    },
    [getStepA, getStepB, stepA]
  );
  return { getStepC, stepC };
};

In the real world... StepB is dependent on StepA's data, both are fetch calls... StepC takes the contents of StepA and StepB and returns an amalgamation of them...

How I can write the stepC hook to process and wait, then process and wait, then process and return?

Upvotes: 0

Views: 101

Answers (2)

sz.mark929
sz.mark929

Reputation: 11

There is a useSWR hook what solve kind of these problems. check this

Upvotes: 1

Patrick Roberts
Patrick Roberts

Reputation: 51826

While I don't believe this is a very composable pattern to begin with, it is possible to make them work somewhat with a bit of effort if you're careful to make your initial values for stepA and stepB falsy:

export const useStepC = () => {
  const { getStepA, stepA } = useStepA();
  const { getStepB, stepB } = useStepB();
  const [stepC, setStepC] = useState();

  const getStepC = useCallback((stepAParam: string) => {
    getStepA(stepAParam);
  }, [getStepA]);

  useEffect(() => {
    if (stepA) {
      getStepB(stepA.stepBId);
    }
  }, [stepA, getStepB]);

  useEffect(() => {
    if (stepA && stepB) {
      setStepC({stepA,stebB});
    }
  }, [stepA, stepB, setStepC])

  return { getStepC, stepC };
};

Problems will most likely occur when there are two concurrent promises pending caused by multiple calls to getStepC() in a short period, and because the way useStepA() and useStepB() are implemented, there is no way to resolve these inherent race conditions.

Upvotes: 2

Related Questions