Custom Fetch Hook With React Hooks

Share:


Source Code

In this tutorial, we’re going to create a custom React Hook that wraps on top of Fetch API.  If you’re not familiar with how React Hooks work, then I recommend you to get a refresher here: Learn React Hooks In 15 Minutes

When I write custom hooks, I like to write the usage first and then fill out the actually custom hook body, so for this example, we’re going to grab some a random user data from our dummy API endpoint provided by reqres.in:

export default function App() {
  const randomID = Math.floor((Math.random() * 10) + 1);
  const apiEndpoint = `https://reqres.in/api/users/${randomID}`;
  const userFetchResponse = useFetch(apiEndpoint, {isLoading: true, data: null});

  if (!userFetchResponse.data || userFetchResponse.isLoading) {
    return 'Loading...';
  }

  const {first_name, last_name, avatar} = userFetchResponse.data.data;

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
          <div>
            <h3>Name: {first_name} {last_name}</h3>
            <div><img src={avatar} alt="avatar" /></div>
          </div>
      </header>
    </div>
  );
}

The key line here is

const userFetchResponse = useFetch(apiEndpoint, {isLoading: true, data: null});

Similar to some of the built in hooks (useState), we expect a result value from the useFetch hook and we pass in some initial values to it, the difference is that we are allowed to pass in any type of parameters we want to this custom hook.  In order to make this flexible, we’ll pass in an arbitrary apiEndpoint param, and a default result state object to it.  It’s easy to see what we expect the result of useFetch hook to return by looking at the default value, our next task is to actually implement it.

Implementing useFetch Hook

Here’s the implementation of useFetch:

function useFetch(url, defaultResponse) {
  const [data, setData] = useState(defaultResponse);

  async function getDataFromAPI() {
    try {
      const res = await fetch(url);
      const data = await res.json();
      setData({
        isLoading: false,
        data
      });
    } catch (e) {
      console.error(e);
      setData({
        isLoading: false,
        data: e
      });
    }
  }

  useEffect(() => {
    getDataFromAPI()
  }, []);

  return data;
}

As you can see, it’s relatively simple. We are wrapping the Fetch api in an async function and set the resulting states in variables initialized by useState.  We then call useEffect hook to run this fetch call once and once only when the component mounts, this is accomplished by passing an empty array to the second parameter of useEffect.  We then return data from this hook, which consists of an object with isLoading and the actual ajax response value.

I know this looks very different from what you are used to with React, this is a cleaner way to express and encapsulate our code.  Hooks promote re-usability because it forces you to think about how your code can be chunked out to be used at other parts of the app.

You Might Also Like

Error, group does not exist! Check your syntax! (ID: 7)