# How to Fetch Data from an API and Display It as Raw Data in React

> Learn to fetch API data in React using useState and useEffect. Display raw JSON data easily with JSON.stringify inside a pre tag for quick debugging and development.

- Repository: [Meta/react](https://github.com/facebook/react)
- Tags: how-to-guide
- Published: 2026-02-16

---

**Use the `useState` hook to store API responses and `useEffect` to trigger fetch requests after component mount, then render the raw JSON using `JSON.stringify` inside a `<pre>` tag.**

Fetching data from an API and displaying it as raw data in React relies on the library's declarative state management system. In the facebook/react repository, the core implementations of the hooks that enable this pattern are located in [`packages/react/src/ReactHooks.js`](https://github.com/facebook/react/blob/main/packages/react/src/ReactHooks.js). By combining `useState` for state storage and `useEffect` for side effects, you create a non-blocking data-fetching flow that displays raw API responses without interfering with the initial render.

## Core Hooks for API Data Fetching

React's function components manage data through hooks. Two specific hooks defined in the React source code handle the complete lifecycle of fetching and displaying external data.

### Managing State with useState

The `useState` hook provides reactive state that persists across renders and triggers UI updates when modified. According to the facebook/react source code, the implementation in [`packages/react/src/ReactHooks.js`](https://github.com/facebook/react/blob/main/packages/react/src/ReactHooks.js) (lines 66-71) defines how React maintains state consistency. When fetching API data, initialize state as `null` or an empty object, then update it via the setter function once the network promise resolves.

### Handling Side Effects with useEffect

The `useEffect` hook executes operations that touch external systems—such as network requests—after React commits changes to the DOM. The implementation in [`packages/react/src/ReactHooks.js`](https://github.com/facebook/react/blob/main/packages/react/src/ReactHooks.js) (lines 87-100) ensures effects run after the paint phase, preventing fetch operations from blocking the initial render. Passing an empty dependency array `[]` ensures the effect executes only once when the component mounts, making it ideal for one-time API calls.

## Fetching and Displaying Raw API Data

To fetch data from an API and display it as raw data in React, combine the hooks with the browser's native Fetch API. The following component demonstrates the complete pattern, including loading states and error handling:

```jsx
import React, { useState, useEffect } from 'react';

export default function ApiViewer() {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('https://api.example.com/items')
      .then(res => {
        if (!res.ok) {
          throw new Error(`HTTP ${res.status}`);
        }
        return res.json();
      })
      .then(json => {
        setData(json);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, []);

  if (loading) return <p>Loading…</p>;
  if (error) return <p>Error: {error}</p>;

  return (
    <pre>{JSON.stringify(data, null, 2)}</pre>
  );
}

```

This example encapsulates the fetch call inside `useEffect` to prevent blocking the initial render, uses `useState` to store the response, and displays the raw JSON using `JSON.stringify` with indentation for readability inside a `<pre>` tag.

## Dynamic Data Fetching with Dependencies

When you need to refetch data based on changing props or state, add those values to the `useEffect` dependency array. This pattern is essential when fetching data from an API and displaying it as raw data in React based on user interaction:

```jsx
export function UserInfo({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    setUser(null);
    fetch(`https://api.example.com/users/${userId}`)
      .then(r => r.json())
      .then(setUser);
  }, [userId]);

  return user ? <pre>{JSON.stringify(user, null, 2)}</pre> : <p>Loading…</p>;
}

```

Adding `userId` to the dependency array ensures React runs the effect whenever the prop updates, keeping the displayed raw data synchronized with the current selection.

## Modern Async/Await Syntax

While promise chaining works correctly, many developers prefer async/await for readability. You can use this syntax inside `useEffect` by defining an inner async function:

```jsx
useEffect(() => {
  async function load() {
    try {
      const res = await fetch('https://api.example.com/items');
      const json = await res.json();
      setData(json);
    } catch (e) {
      setError(e.message);
    } finally {
      setLoading(false);
    }
  }
  load();
}, []);

```

Both promise chaining and async/await are fully supported in React's effect system. The choice depends on your team's coding standards and error-handling preferences.

## Summary

- **Use `useState`** to hold API data, loading states, and errors, triggering re-renders when values change according to the implementation in [`packages/react/src/ReactHooks.js`](https://github.com/facebook/react/blob/main/packages/react/src/ReactHooks.js).
- **Use `useEffect`** with an empty dependency array to execute fetch calls after the initial paint, preventing render blocking as defined in [`packages/react/src/ReactHooks.js`](https://github.com/facebook/react/blob/main/packages/react/src/ReactHooks.js) (lines 87-100).
- **Display raw data** by rendering `JSON.stringify(data, null, 2)` inside a `<pre>` tag to preserve formatting and indentation.
- **Handle dynamic fetching** by adding dependencies to the effect array, causing React to refetch when props or state change.
- **Choose your syntax** between promise chaining and async/await based on readability needs; both work identically within the React hook lifecycle.

## Frequently Asked Questions

### How do I prevent my React component from rendering before data loads?

Initialize your state to `null` or a loading indicator, then conditionally render content based on that state. Return a loading message when the data is `null`, and render the actual content—including your raw JSON display—only after the fetch promise resolves and updates state via the setter function.

### Why must I use `useEffect` instead of calling fetch directly in the component body?

Calling fetch directly in the component body would execute during every render, creating infinite loops and blocking the main thread. The `useEffect` hook—specifically implemented in [`packages/react/src/ReactHooks.js`](https://github.com/facebook/react/blob/main/packages/react/src/ReactHooks.js)—guarantees that side effects run after React commits the DOM, ensuring the initial paint completes before network requests begin.

### Can I display raw API data without using `JSON.stringify`?

While you can attempt to render objects directly in JSX, React will throw an error because JSX cannot render objects as children. You must convert the data to a string first. `JSON.stringify(data, null, 2)` is the standard approach for displaying raw JSON because it formats the output with indentation, making it readable when wrapped in a `<pre>` tag.

### How do I handle API errors gracefully in React?

Track error state using a separate `useState` variable initialized to `null`. In your `useEffect` fetch logic, use a `.catch()` block (or try/catch with async/await) to capture errors and update the error state. Conditionally render an error message in your JSX when the error state exists, providing clear feedback without crashing the application.