Displaying API Data in ReactJS Components

This guide will walk you through fetching, storing, and displaying API data in ReactJS components, including best practices and practical exercises to enhance your understanding.

Welcome to the world of fetching and displaying data from APIs in ReactJS components! This guide is designed to take you through the entire process, from setting up your environment to styling the data, using engaging and practical examples. By the end of this tutorial, you'll have a solid grasp of how to work with APIs in React, making your applications more dynamic and user-friendly.

Understanding API Data

What is API Data?

API stands for Application Programming Interface, which allows different software applications to communicate with each other. API data refers to the information that an API provides. This data can be in various formats, but JSON (JavaScript Object Notation) is the most common. For instance, an API might provide weather data, user information, product listings, and more.

Why Display API Data in Components?

Displaying API data in React components allows you to create dynamic applications that can fetch and display the latest data from external sources. This is essential for building real-world applications that interact with servers, databases, and other services. Imagine a news website that displays the latest articles or a weather app that shows current weather conditions.

Setting Up Your Environment

Creating a React Application

Before we dive into fetching API data, we need to set up a React application. You can do this using Create React App, which sets up everything for you. Open your terminal and run the following commands:

npx create-react-app my-react-app
cd my-react-app
npm start

This will create a new React application called my-react-app and start the development server. Your default browser will open to http://localhost:3000, where you'll see the default React welcome page.

Preparing the Component Structure

For displaying API data, we'll create a new component called DataFetcher.js. Inside your src directory, create a file named DataFetcher.js.

// src/DataFetcher.js

import React from 'react';

const DataFetcher = () => {
  return (
    <div>
      <h1>Data Fetcher Component</h1>
      <p>Here we will display API data</p>
    </div>
  );
};

export default DataFetcher;

Now, include this component in your main App.js file.

// src/App.js

import React from 'react';
import DataFetcher from './DataFetcher';

function App() {
  return (
    <div className="App">
      <DataFetcher />
    </div>
  );
}

export default App;

Fetching Data and Storing it in State

Using useState Hook

React provides hooks that allow you to add state and other React features to your components. The useState hook lets you add React state to function components.

// Importing useState from react
import React, { useState } from 'react';

const DataFetcher = () => {
  // Creating a state variable 'data' and a function 'setData' to update it
  const [data, setData] = useState(null);

  return (
    <div>
      <h1>Data Fetcher Component</h1>
      <p>Here we will display API data</p>
    </div>
  );
};

export default DataFetcher;

Using useEffect Hook

The useEffect hook allows you to perform side effects in function components, such as data fetching. We'll use it to fetch data from an API when the component mounts.

Fetching Data from an API

Let's use the fetch API to get data from a public API. For this example, we'll use the JSONPlaceholder API, which is a free online REST API that you can use for testing and prototyping.

// Importing useState and useEffect from react
import React, { useState, useEffect } from 'react';

const DataFetcher = () => {
  const [data, setData] = useState(null);

  useEffect(() => {
    // Fetching data from JSONPlaceholder API
    fetch('https://jsonplaceholder.typicode.com/posts')
      .then(response => response.json())
      .then(data => setData(data));
  }, []); // Empty dependency array means this effect runs only once after the initial render

  return (
    <div>
      <h1>Data Fetcher Component</h1>
      <p>Here we will display API data</p>
    </div>
  );
};

export default DataFetcher;

In this example, the useEffect hook is used to fetch data from the JSONPlaceholder API when the component mounts. The fetch function is used to make a GET request to the API, and the response is converted to JSON. Once the data is fetched, it is stored in the data state variable using the setData function.

Setting State with Fetched Data

We've already covered setting the state with fetched data in the previous example. Inside the useEffect hook, after the data is fetched and converted to JSON, it is passed to the setData function to update the data state variable.

Displaying Data in the Component

Basic Rendering Techniques

Once you have the data stored in the state, you can render it in your component. Let's display the fetched posts on the webpage.

// Displaying the fetched data
const DataFetcher = () => {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts')
      .then(response => response.json())
      .then(data => setData(data));
  }, []);

  return (
    <div>
      <h1>Data Fetcher Component</h1>
      {data && data.map(post => (
        <div key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.body}</p>
        </div>
      ))}
    </div>
  );
};

export default DataFetcher;

In this example, we're mapping over the data array and rendering each post's title and body. The key prop is important for React to identify which items have changed, are added, or are removed. Here, we're using the id of each post as the key.

Mapping Over Arrays to Display Data

When you fetch data from an API, it's often received as an array of objects. To display this data, you can map over the array and return a JSX element for each object.

{data && data.map(post => (
  <div key={post.id}>
    <h2>{post.title}</h2>
    <p>{post.body}</p>
  </div>
))}

In this code snippet, data.map(post => ...) iterates over each post in the data array. For each post, it returns a div containing the title and body of the post. The key prop is set to post.id to ensure React can track each post uniquely.

Conditional Rendering for Data Availability

Before rendering the data, you should check if it has been fetched and stored in the state. You can use conditional rendering to display a loading message while the data is being fetched and show the data once it's available.

const DataFetcher = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts')
      .then(response => response.json())
      .then(data => {
        setData(data);
        setLoading(false);
      })
      .catch(error => {
        console.error('Error fetching data:', error);
        setLoading(false);
      });
  }, []);

  return (
    <div>
      <h1>Data Fetcher Component</h1>
      {loading ? (
        <p>Loading data...</p>
      ) : data ? (
        data.map(post => (
          <div key={post.id}>
            <h2>{post.title}</h2>
            <p>{post.body}</p>
          </div>
        ))
      ) : (
        <p>No data available</p>
      )}
    </div>
  );
};

export default DataFetcher;

In this example, we've introduced a loading state variable. Initially, loading is set to true. Once the data is fetched, loading is set to false. We then use conditional rendering to show a loading message while loading is true, the fetched data when data is available, and a "No data available" message otherwise.

Styling API Data

Basic CSS for List Items

You can add CSS to style the data displayed in your components. Let's add some basic styles to the posts displayed in our DataFetcher component.

First, create a CSS file named DataFetcher.css.

/* src/DataFetcher.css */

.post {
  border: 1px solid #ccc;
  padding: 16px;
  margin-bottom: 16px;
  border-radius: 8px;
  background-color: #f9f9f9;
}

.post h2 {
  margin: 0 0 8px;
}

.post p {
  margin: 0;
}

Next, import this CSS file into your DataFetcher.js file.

// src/DataFetcher.js

import React, { useState, useEffect } from 'react';
import './DataFetcher.css';

const DataFetcher = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts')
      .then(response => response.json())
      .then(data => {
        setData(data);
        setLoading(false);
      })
      .catch(error => {
        console.error('Error fetching data:', error);
        setLoading(false);
      });
  }, []);

  return (
    <div>
      <h1>Data Fetcher Component</h1>
      {loading ? (
        <p>Loading data...</p>
      ) : data ? (
        data.map(post => (
          <div className="post" key={post.id}>
            <h2>{post.title}</h2>
            <p>{post.body}</p>
          </div>
        ))
      ) : (
        <p>No data available</p>
      )}
    </div>
  );
};

export default DataFetcher;

Here, we've added a CSS class post to each post to apply styles. The styles are defined in the DataFetcher.css file.

Dynamic Styling Based on Data

You can also apply dynamic styles based on the data. For example, you might want to display different border colors based on the post's length.

// Dynamic styling based on post length
const DataFetcher = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts')
      .then(response => response.json())
      .then(data => {
        setData(data);
        setLoading(false);
      })
      .catch(error => {
        console.error('Error fetching data:', error);
        setLoading(false);
      });
  }, []);

  return (
    <div>
      <h1>Data Fetcher Component</h1>
      {loading ? (
        <p>Loading data...</p>
      ) : data ? (
        data.map(post => (
          <div
            className="post"
            style={{ borderColor: post.body.length > 250 ? 'red' : 'blue' }}
            key={post.id}
          >
            <h2>{post.title}</h2>
            <p>{post.body}</p>
          </div>
        ))
      ) : (
        <p>No data available</p>
      )}
    </div>
  );
};

export default DataFetcher;

In this example, we're adding a dynamic style to the div element representing each post. If the post's body is longer than 250 characters, the border color is set to red; otherwise, it's set to blue. This is a simple way to apply dynamic styles based on data conditions.

Practice Exercises

Fetching and Displaying Data from a Public API

Now, it's your turn to practice fetching and displaying data from a public API. Try using the JSONPlaceholder API for comments and display them in your component.

First, create a new component called CommentFetcher.js.

// src/CommentFetcher.js

import React, { useState, useEffect } from 'react';
import './DataFetcher.css'; // Reusing the same CSS for consistency

const CommentFetcher = () => {
  const [comments, setComments] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/comments')
      .then(response => response.json())
      .then(comments => {
        setComments(comments);
        setLoading(false);
      })
      .catch(error => {
        console.error('Error fetching comments:', error);
        setLoading(false);
      });
  }, []);

  return (
    <div>
      <h1>Comment Fetcher Component</h1>
      {loading ? (
        <p>Loading comments...</p>
      ) : comments ? (
        comments.map(comment => (
          <div className="post" key={comment.id}>
            <h2>{comment.name}</h2>
            <p>{comment.body}</p>
          </div>
        ))
      ) : (
        <p>No comments available</p>
      )}
    </div>
  );
};

export default CommentFetcher;

In this exercise, we've created a new component called CommentFetcher that fetches comments from the JSONPlaceholder API. We're reusing the same CSS styles defined in DataFetcher.css.

Next, include this new component in your App.js file.

// src/App.js

import React from 'react';
import DataFetcher from './DataFetcher';
import CommentFetcher from './CommentFetcher';

function App() {
  return (
    <div className="App">
      <DataFetcher />
      <CommentFetcher />
    </div>
  );
}

export default App;

Now, your application will display both posts and comments fetched from the API.

Adding Basic Styling to the Fetched Data

Let's add some basic styling to the comments fetched from the API. We'll create a new CSS file called CommentFetcher.css and import it into CommentFetcher.js.

/* src/CommentFetcher.css */

.comment {
  border: 1px solid #aaa;
  padding: 16px;
  margin-bottom: 16px;
  border-radius: 4px;
  background-color: #e9e9e9;
}

.comment h2 {
  margin: 0 0 8px;
  font-size: 18px;
}

.comment p {
  margin: 0;
  font-size: 14px;
}

Import the CSS file in your CommentFetcher.js.

// src/CommentFetcher.js

import React, { useState, useEffect } from 'react';
import './CommentFetcher.css';

const CommentFetcher = () => {
  const [comments, setComments] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/comments')
      .then(response => response.json())
      .then(comments => {
        setComments(comments);
        setLoading(false);
      })
      .catch(error => {
        console.error('Error fetching comments:', error);
        setLoading(false);
      });
  }, []);

  return (
    <div>
      <h1>Comment Fetcher Component</h1>
      {loading ? (
        <p>Loading comments...</p>
      ) : comments ? (
        comments.map(comment => (
          <div className="comment" key={comment.id}>
            <h2>{comment.name}</h2>
            <p>{comment.body}</p>
          </div>
        ))
      ) : (
        <p>No comments available</p>
      )}
    </div>
  );
};

export default CommentFetcher;

Here, we've created a new CSS class called comment and applied it to each comment div. This styles the comments differently from the posts.

Summary

Key Takeaways

  • API Data: Data provided by an API that can be fetched and displayed in React components.
  • useState Hook: Used to add state to functional components.
  • useEffect Hook: Used to perform side effects, such as data fetching, in functional components.
  • Conditional Rendering: A technique to conditionally render JSX based on the state of the component.
  • Dynamic Styling: Applying styles based on the data or state of the application.

Next Steps

  • Experiment with different APIs and display their data in your React components.
  • Try adding more complex data processing and rendering techniques.

Additional Resources

Useful Tools and Libraries

  • Axios: A promise-based HTTP client for the browser and Node.js.
  • React Bootstrap: A collection of reusable React components styled with Bootstrap.
  • Styled Components: A library for styling React components using tagged template literals.

Feel free to explore these resources to deepen your understanding and enhance your React applications. Happy coding!