The correct way to fetch data from API

ยท

5 min read

Introduction

This article will tell you how to correctly fetch data from APIs in React. From making efficient API requests to delivering good user feedback, it covers it all.

Tech Stack

I am going to use Chakra UI for UI components, you can use any UI Component library you like or even create your own UI Components. I will be using a public Joke API to demonstrate you the process. You can take a look at it's swagger docs here.

Creating React App

Let us first create a React App with Chakra-ui's template. Let's name it Punbytes. Type the following in your command line.

npx create-react-app punbytes --template @chakra-ui

After the above CLI code has been successfully executed. It would create a boilerplate for you to work on which would look like this.

Boilerplate

Cleaning the code

The only thing which I'll be using here is the color mode switcher, which let's you switch color modes. I am just keeping it for my personal preference. If you want you can remove it. After that I'll just create a logo using <Heading> component of Chakra ui. Now our App.js would look like this

import React from 'react';
import {
  ChakraProvider,
  theme,
  Flex,
  Heading,
} from '@chakra-ui/react';
import { ColorModeSwitcher } from './ColorModeSwitcher';
function App() {
  return (
    <ChakraProvider theme={theme}>
      <Flex justifyContent={'space-between'} p={5}>
        <Heading>
          Punbytes
        </Heading>
        <ColorModeSwitcher justifySelf="flex-end" />
      </Flex>
    </ChakraProvider>
  );
}

export default App;

Creating some front-end for the API

We can add a big text in the front containing the Joke and a button which fetches new joke.

import React from 'react';
import {
  ChakraProvider,
  theme,
  Flex,
  Heading,
  Text,
  Button,
} from '@chakra-ui/react';
import { ColorModeSwitcher } from './ColorModeSwitcher';
function App() {
  return (
    <ChakraProvider theme={theme}>
      <Flex justifyContent={'space-between'} p={5}>
        <Heading>Punbytes</Heading>
        <ColorModeSwitcher justifySelf="flex-end" />
      </Flex>
      <Flex justifyContent={'center'} alignItems={'center'} minH={'75vh'}>
        <Text
          fontSize={'3xl'}
          textAlign="center"
        >
          Joke
        </Text>
      </Flex>
      <Flex
        justifyContent={['center', 'center', 'flex-end', 'flex-end']}
        mr={10}
        mb={12}
      >
        <Button> Another One</Button>
      </Flex>
    </ChakraProvider>
  );
}

export default App;

Our webpage would look like this.

Front Page

Fetching data from the API

To fetch data we'll make use of fetch() along with async await for asynchronous programming. But first we need to create some states that will be updated. We'll require a state for joke, a state to show loading and a state for error. As we are using functional components, we'll make use of useState Hook to create state. We'll add the following code to the top level of our functional component.

    const [joke, setJoke] = useState('');
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState('');

Now that we have states, let us create the function that would retrieve data from the API. We'll create an asynchronous function using async await.

const getJoke = async () => {
    setLoading(true);
    try {
      const res = await fetch(
        'https://v2.jokeapi.dev/joke/Programming?type=single'
      );
      const data = await res.json();
      setJoke(data.joke);
    } catch (error) {
      console.error(error);
      setError(error);
    }
    setLoading(false);
  };

This function is going to be invoked at the load time, as well as on clicking another one button. To invoke it at the load time we'll call this function in a useEffect Hook for one time.

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

The empty dependency array denotes that the useEffect should run only once.

Now we can also add this function to onClick of our Another One Button.

<Button onClick={getJoke}> Another One</Button>

Updating the front-end

Now we can update the front-end according to our states. We'll first add a loader, which makes use of loading state. We'll make use of <Spinner> component to display loading.

{loading ? (
        <Flex
          minH={'75vh'}
          fontSize={'2xl'}
          justifyContent={'center'}
          alignItems={'center'}
        >
          <Spinner size={'xl'} />
        </Flex>
      ) :  (
        <>
          <Flex justifyContent={'center'} alignItems={'center'} minH={'75vh'}>
            <Text
              fontSize={'3xl'}
              textAlign="center"

            >
              {joke}
            </Text>
          </Flex>
          <Flex justifyContent={['center','center','flex-end','flex-end']} mr={10} mb={12}>
            <Button onClick={getJoke}> Another One</Button>
          </Flex>
        </>
      )}

Now we'll also add error display, in case of any error. For that we'll make use of error State. For the front-end part we'll use <Alert> component of Chakra UI.

{loading ? (
        <Flex
          minH={'75vh'}
          fontSize={'2xl'}
          justifyContent={'center'}
          alignItems={'center'}
        >
          <Spinner size={'xl'} />
        </Flex>
      ) : error ? (
        <Alert status="error">
          <AlertIcon />
          <AlertTitle>{error.title}</AlertTitle>
          <AlertDescription>{error.message}</AlertDescription>
        </Alert>
      ) : (
        <>
          <Flex justifyContent={'center'} alignItems={'center'} minH={'75vh'}>
            <Text
              fontSize={'3xl'}
              textAlign="center"
            >
              {joke}
            </Text>
          </Flex>
          <Flex justifyContent={['center','center','flex-end','flex-end']} mr={10} mb={12}>
            <Button onClick={getJoke}> Another One</Button>
          </Flex>
        </>
      )}

The final code would look like this.

import React, { useEffect, useState } from 'react';
import {
  ChakraProvider,
  theme,
  Flex,
  Heading,
  Text,
  Button,
  Spinner,
  Alert,
  AlertIcon,
  AlertTitle,
  AlertDescription,
} from '@chakra-ui/react';
import { ColorModeSwitcher } from './ColorModeSwitcher';
function App() {
  const [joke, setJoke] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');
  const getJoke = async () => {
    setLoading(true);
    try {
      const res = await fetch(
        'https://v2.jokeapi.dev/joke/Programming?type=single'
      );
      const data = await res.json();
      setJoke(data.joke);
    } catch (error) {
      console.error(error);
      setError(error);
    }
    setLoading(false);
  };
  useEffect(() => {
    getJoke();
  }, []);

  return (
    <ChakraProvider theme={theme}>
      <Flex justifyContent={'space-between'} p={5}>
        <Heading>Punbytes</Heading>
        <ColorModeSwitcher justifySelf="flex-end" />
      </Flex>
      {loading ? (
        <Flex
          minH={'75vh'}
          fontSize={'2xl'}
          justifyContent={'center'}
          alignItems={'center'}
        >
          <Spinner size={'xl'} />
        </Flex>
      ) : error ? (
        <Alert status="error">
          <AlertIcon />
          <AlertTitle>{error.title}</AlertTitle>
          <AlertDescription>{error.message}</AlertDescription>
        </Alert>
      ) : (
        <>
          <Flex justifyContent={'center'} alignItems={'center'} minH={'75vh'}>
            <Text fontSize={'3xl'} textAlign="center">
              {joke}
            </Text>
          </Flex>
          <Flex
            justifyContent={['center', 'center', 'flex-end', 'flex-end']}
            mr={10}
            mb={12}
          >
            <Button onClick={getJoke}> Another One</Button>
          </Flex>
        </>
      )}
    </ChakraProvider>
  );
}

export default App;

The output would be like this.

Output

Loading

Conclusion

We have now covered a brief intro to fetching data from APIs. Further we can analyze and create specific errors for Status Codes returned by HTTP Request. We can also look into the cleaning part of useEffect when we are fetching data from API based on a dependency. Typical example would be autocomplete feature.

Thank you for reading ๐Ÿ˜ƒ

ย