React API Call

Summary: in this tutorial, you will learn to call API in a React app using the built-in Fetch API provided by web browsers.

Introduction to Wikipedia Search React App

We’ll create a new React app that allows you to search Wikipedia articles. To do that, the React app needs to call Wikipedia Search API:

react api call - wikipedia search app

The React app will look like the following:

react api call - wikipedia search app prototype

We can break down this React app into the following components:

react api call - wikipedia search

Here’s the component hierarchy:

In this component hierarchy:

  • The App component is a parent component that includes other components.
  • The SearchBar component allows you to type a search term and press the Enter key to submit it.
  • The ArticleList component is responsible for rendering the search results, which include a list of articles.
  • The Article component renders each article in the search results.

Props and State Design

There are some questions we need to answer before creating the app:

  • What is the state of the application?
  • Which component should handle the API call?
  • How should we design the props system?

The app displays a list of articles so it should have an array of articles as a state variable:

const [articles, setArticles] = useState([]);Code language: JavaScript (javascript)

Since the App component uses the ArticleList component to render the article list, it should pass the articles array as a prop to the ArticleList.

Additionally, the ArticleList should pass each article as a prop to the Article component for rendering each article.

If we call Wikipedia API in the SearchBar component, we can get a list of articles. But how do we pass the article list from the SearchBar component to the App component?

Typically, React allows us to pass props from parent components to the child components, not from the child component to the parent component or between sibling components.

To overcome this limitation, we can pass a callback function from the App component to the SearchBar component as a prop.

When the user submits the search form, we can call the callback function onSearch to update the articles state of the App component:

react api call - states & props design

Create a new React app

First, open a terminal on your computer and create a new React app using the create-react-app command:

npx create-react-app wiki-searchCode language: JavaScript (javascript)

Next, delete all files in the src directory.

Then, create a new index.js file in the src directory and add the following code:

import ReactDOM from 'react-dom/client';
import App from './App.js';

const el = document.querySelector('#root');
const root = ReactDOM.createRoot(el);

root.render(<App />);Code language: JavaScript (javascript)

The index.js file renders the App component on the screen.

After that, create a new file named App.js in the src directory with the following code:

const App = () => {
  return <div>Wikipedia Search</div>;
};

export default App;Code language: JavaScript (javascript)

Finally, run the React app by running the following command in the terminal:

npm startCode language: JavaScript (javascript)

You’ll see the new React app on the web browser at http://localhost:3000.

Calling an API

There are several ways to call an API from a React app. The simplest one is to use the native Fetch API provided by the web browser because we don’t need to install any third-party package.

First, call the fetch() method by passing the API endpoint:

const response = await fetch(url);Code language: JavaScript (javascript)

Second, call the json() method of the Response object to parse the JSON body contents:

const results = await response.json();Code language: JavaScript (javascript)

Third, return the parsed JSON data:

return results;Code language: JavaScript (javascript)

Calling Wikipedia Search API

First, create a new file in the src directory named api.js:

Second, define a search() function that calls Wikipedia Search API for a specified search term and returns an array of articles:

export const search = async (searchTerm) => {
  const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srsearch=${searchTerm}`;
  const response = await fetch(url);
  const results = await response.json();
  return results.query.search;
};
Code language: JavaScript (javascript)

How it works.

Step 1. Define a search function that accepts a search term:

export const search = async (searchTerm) => {
   // ...
}Code language: JavaScript (javascript)

Step 2. Construct the API endpoint by concatenating the API URL with the search term:

const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srlimit=10&srsearch=${searchTerm}`;Code language: JavaScript (javascript)

Step 3. Return JSON data from the API:

const response = await fetch(url);
const results = await response.json();
return results.query.search;Code language: JavaScript (javascript)

The search results include pageid, title, and snippet. The title and snippet may contain HTML tags.

To strip the HTML tags, we can create a new file util.js in the src directory and define the stripHTML() function as follows:

export const stripHtml = (html) => {
  let div = document.createElement('div');
  div.innerHTML = html;
  return div.textContent;
};Code language: JavaScript (javascript)

We’ll use the stripHTML in the Article component to strip HTML from the title and snippet.

Create React components

We’ll create the components for the React app.

App component

The following App component includes the SearchBar and ArticleList components:

import { useState } from 'react';
import { search } from './api';
import SearchBar from './components/SearchBar';
import ArticleList from './components/ArticleList';
import './App.css';
import logo from './wikipedia-logo.png';

const App = () => {
  const [articles, setArticles] = useState([]);

  const handleSearch = async (searchTerm) => {
    const results = await search(searchTerm);
    setArticles(results);
  };

  return (
    <>
      <header>
        <img src={logo} alt="wikipedia" />
        <h1>Wikipedia Search</h1>
        <SearchBar onSearch={handleSearch} />
      </header>
      <main id="searchResult">
        <ArticleList articles={articles} />
      </main>
    </>
  );
};

export default App;Code language: JavaScript (javascript)

How it works.

Step 1. Import the useState function from the react library because the App will hold some piece of state.

import { useState } from 'react';Code language: JavaScript (javascript)

Step 2. Import the search function from the api.js module:

import { search } from './api';Code language: JavaScript (javascript)

Step 3. Import the SearchBar and ArticleList components:

import SearchBar from './components/SearchBar';
import ArticleList from './components/ArticleList';Code language: JavaScript (javascript)

Step 4. Import the App.css and wikipedia-logo.png files:

import './App.css';
import logo from './wikipedia-logo.png';Code language: JavaScript (javascript)

Step 5. Define the App component:

const App = () => {
   // ...
};Code language: JavaScript (javascript)

Step 5. Define a piece of state (articles) which is an array of articles, and initialize its default value to an empty array:

const [articles, setArticles] = useState([]);Code language: JavaScript (javascript)

Step 6. Define a handleSearch() function that calls the search function to get the search results and update the articles state with these results:

const handleSearch = async (searchTerm) => {
    const results = await search(searchTerm);
    setArticles(results);
};Code language: JavaScript (javascript)

Step 7. Return JSX that includes a logo, a heading, a SearchBar component, and an ArticleList component.

return (
  <>
    <header>
      <img src={logo} alt="wikipedia" />
      <h1>Wikipedia Search</h1>
      <SearchBar onSearch={handleSearch} />
    </header>
    <main id="searchResult">
      <ArticleList articles={articles} />
    </main>
  </>
);Code language: JavaScript (javascript)

In the JSX:

  • Pass the handleSearch function to the onSearch prop of the SearchBar component.
  • Pass the articles state as a prop to the ArticleList component.

Showing the loading state

When you call an API, it takes some time to get the result back, so showing a loading indicator is important for a better user experience.

To do that, we add a new state variable isLoading to the App component:

const [isLoading, setIsLoading] = useState(false);Code language: JavaScript (javascript)

Before calling the search function, we set the value of isLoading to true and after getting the result we set its value to false:

const handleSearch = async (searchTerm) => {
    setIsLoading(true);
    const results = await search(searchTerm);
    setArticles(results);
    setIsLoading(false);
};Code language: JavaScript (javascript)

To show the loading indicator, we use a conditional rendering as follows:

{isLoading && <p>Loading...</p>}Code language: HTML, XML (xml)

Handling errors

When calling an API, various errors may occur such as a network disconnect or server outage. That’s why it’s important to show users an error message when something goes wrong.

To handle this, we can add a new state variable to the App component and update it whenever an error occurs:

const [error, setError] = useState(null);Code language: JavaScript (javascript)

To handle errors, we can use the try…catch statement. If an error occurs, we can update the error state variable:

const handleSearch = async (searchTerm) => {
  setIsLoading(true);
  try {
    const results = await search(searchTerm);
    setArticles(results);
  } catch (err) {
    setError('Something went wrong. Please try again.');
  } finally {
    setIsLoading(false);
  }
};Code language: JavaScript (javascript)

In this code, we set the error state variable to an error message in the catch block. To render the error message, we can use a conditional rendering:

{error && <p className="error">{error}</p>}Code language: HTML, XML (xml)

Here’s the complete App.js component:

import { useState } from 'react';
import SearchBar from './components/SearchBar';
import ArticleList from './components/ArticleList';
import { search } from './api';
import './App.css';
import logo from './wikipedia-logo.png';

const App = () => {
  const [articles, setArticles] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  const handleSearch = async (searchTerm) => {
    setIsLoading(true);
    try {
      const results = await search(searchTerm);
      setArticles(results);
    } catch (err) {
      setError('Something went wrong. Please try again.');
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <>
      <header>
        <img src={logo} alt="wikipedia" />
        <h1>Wikipedia Search</h1>
        <SearchBar onSearch={handleSearch} />
      </header>

      <main id="searchResult">
        {isLoading && <p>Loading...</p>}
        {error && <p className="error">{error}</p>}
        <ArticleList articles={articles} />
      </main>
    </>
  );
};

export default App;Code language: JavaScript (javascript)

Note that you may consider incorporating the AbortController to abort the previous search request if users start a new one

SearchBar component

The SearchBar component will allow users to enter a search term and run a function to call the API for searching:

import { useState } from 'react';

const SearchBar = () => {
  const [searchTerm, setSearchTerm] = useState('');

  const handleSubmit = (event) => {
    event.preventDefault();
    onSearch(searchTerm);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="search"
        name="searchTerm"
        id="searchTerm"
        placeholder="Enter a search term..."
        value={searchTerm}
        onChange={(event) => {
          setSearchTerm(event.target.value);
        }}
      />
    </form>
  );
};

export default SearchBar;Code language: JavaScript (javascript)

How it works.

Step 1. Import the useState function from the react library:

import { useState } from 'react';Code language: JavaScript (javascript)

Step 2. Define the SearchBar component that accepts a function onSearch as a prop:

const SearchBar = ({ onSearch }) => {
   // ..
}Code language: JavaScript (javascript)

Step 3. Define a searchTerm state for the SearchBar component and initialize its default value to an empty string:

 const [searchTerm, setSearchTerm] = useState('');Code language: JavaScript (javascript)

Step 4. Create an event handler that handles the submit event:

 const handleSubmit = (e) => {
    e.preventDefault();
    onSearch(searchTerm);
  };Code language: JavaScript (javascript)

In the submit event, we call the e.preventDefault() to prevent the whole page from reloading when users submit the form and call the onSearch function with the searchTerm state as the argument.

Step 5. Return JSX that includes a form and an input element:

return (
    <form onSubmit={handleSubmit}>
      <input
        type="search"
        name="searchTerm"
        id="searchTerm"
        placeholder="Enter a search term..."
        value={searchTerm}
        onChange={(e) => {
          setSearchTerm(e.target.value);
        }}
      />
    </form>
  );Code language: JavaScript (javascript)

In the JSX:

  • Wire the handleSubmit event handler to the onSubmit prop of the form.
  • Call the setSearchTerm to update the state in the change event handler of the input element. The e.target.value returns the current value of the input element. The setSearchTerm function will assign a new input value to the searchTerm state of the component.

Step 6. Export the SearchBar component using a default export:

export default SearchBar;Code language: JavaScript (javascript)

ArticleList component

The ArticleList component displays a list of Article components:

import Article from './Article';

const ArticleList = ({ articles }) => {
  const renderedArticles = articles.map((article) => {
    return <Article key={article.pageid} article={article} />;
  });

  return <div>{renderedArticles}</div>;
};

export default ArticleList;Code language: JavaScript (javascript)

How it works.

Step 1. Import the Article component:

import Article from './Article';Code language: JavaScript (javascript)

Step 2. Define the ArticleList component that accepts an array of articles as a prop and renders each article using the Article component:

const ArticleList = ({ articles }) => {
  const renderedArticles = articles.map((article) => {
    return <Article key={article.pageid} article={article} />;
  });

  return <div>{renderedArticles}</div>;
};Code language: JavaScript (javascript)

Step 3. Export the ArticleList component as a default component:

export default ArticleList;Code language: JavaScript (javascript)

Article component

The Article component renders an article:

import { stripHtml } from '../util';

const Article = ({ article }) => {
  const url = `https://en.wikipedia.org/?curid=${article.pageid}`;
  const title = stripHtml(article.title);
  const snippet = stripHtml(article.snippet);

  return (
    <article>
      <a href={url} title={title}>
        <h2>{title}</h2>
      </a>
      <div className="summary">{snippet}...</div>
    </article>
  );
};

export default Article;Code language: JavaScript (javascript)

How it works.

Step 1. Import the stripHTML function from the util library:

import { stripHtml } from '../util';Code language: JavaScript (javascript)

Step 2. Create an Article component that renders the article prop:

const Article = ({ article }) => {
  const url = `https://en.wikipedia.org/?curid=${article.pageid}`;
  const title = stripHtml(article.title);
  const snippet = stripHtml(article.snippet);

  return (
    <article>
      <a href={url} title={title}>
        <h2>{title}</h2>
      </a>
      <div className="summary">{snippet}...</div>
    </article>
  );
};Code language: JavaScript (javascript)

In the Article component:

  • Construct a URL to an article on Wikipedia.
  • Strip HTML tags from the title and snippet of the article object.
  • Return the <article> JSX element.

Step 3. Export the Article component as a default export:

export default Article;Code language: JavaScript (javascript)

Download the Wiki Search source code.

Summary

  • Use native browser Fetch API to call an external API.
Was this tutorial helpful ?