React - Fetching promises from the state???
Tags: javascript, react, webdev, tutorial
Published: 2022-08-07 19:36:52

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:

```jsx
const [state, setState] = useState();
```

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:

```jsx
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>
  );
}
```

And that will work!

## useStatePromise

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

```jsx
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];
}
```

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](https://codesandbox.io/embed/promise-state-7qd2n7?autoresize=1&expanddevtools=1&fontsize=14&hidenavigation=1&theme=dark)

{% embed https://codesandbox.io/embed/promise-state-7qd2n7?autoresize=1&expanddevtools=1&fontsize=14&hidenavigation=1&theme=dark %}

---

## Bonus - useRefPromise

Since I was there, I also played around the `useRef`

```jsx
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;
}
```

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](https://unsplash.com/@womanizer?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/promise?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)