DEV Community 👩‍💻👨‍💻

Cover image for React - Fetching promises from the state???
Bruno Noriller
Bruno Noriller

Posted on • Originally published at Medium

React - Fetching promises from the state???

As people say: “It’s only stupid if it doesn’t work”.


The basics you might not know

First thing, initializing

It’s convention to initialize a state as:

const [state, setState] = useState();
Enter fullscreen mode Exit fullscreen mode

But… useState is just a function that returns an array and you can dump it anywhere you want as long as you don’t violate the rule of hooks.

And while we are at it, you can initialize it with a function, that function will run only once no matter what and that’s it.

Second thing, what can be a state

ANYTHING! (as far as I know =p)

What about a promise then? Yes, you can have promises in a state, of course, that you can’t unpack them inside the JSX part.

First version

With that in mind, you’re probably thinking something along this lines:

function FirstVersion() {
  const [state, setState] = useState(() =>
    fakeFetch("First Version!")
      .then((val) => setState(val))
      .catch((err) => setState(err))
  );
  return (
    <div style={{ marginTop: "2em" }}>
      {
        (state instanceof Promise) 
          ? "Loading First Version Component..." 
          : state
      }
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

And that will work!

useStatePromise

So, I’ve played around and made this custom hook:

import { useEffect, useState } from "react";

export function useStatePromise(promise) {
  const [error, setError] = useState(null);
  const [value, setValue] = useState(() => {
    promise
      .then((val) => setValue(val))
      .catch(setError);
  });
  const [newValue, setNewValue] = useState(null);

  useEffect(() => {
    if (newValue instanceof Promise) {
      newValue.then(setValue).catch(setError);
    } else {
      setValue(newValue);
    }
  }, [newValue, setValue]);

  return [value, setNewValue, error];
}
Enter fullscreen mode Exit fullscreen mode

Adding to what I did in the first version, first I extracted that into a custom hook, then I added a way to be able to change the state, this is done by using another state to keep the promise until finished.


Example project

See in CodeSandbox


Bonus - useRefPromise

Since I was there, I also played around the useRef

import { useRef } from "react";

export function useRefPromise(promise) {
  const ref = useRef(promise.then((val) => (ref.current = val)));

  if (ref.current instanceof Promise) {
    return null;
  }

  return ref.current;
}
Enter fullscreen mode Exit fullscreen mode

If you’ve opened the example, you will see it works… but be careful!

It only works because the useEffect keeps forcing renders that will make it pick up the ref latest values. So… in a few scenarios, it would work.

Comment out the useEffect with setInterval and see how it would behave then.


Outro

React functions are just that, functions. Yes, there are a lot of things happening in the background, but as far as you’re concerned, it’s functions and so you can do some crazy stuff with it.

Then again, all of these are probably some bad ideas that you shouldn’t really use unless you actually have a case that would, someway somehow, benefit from it.


Cover Photo by Womanizer Toys on Unsplash

Top comments (0)

🌚 Life is too short to browse without dark mode