Fetching data with React hooks

In this tutorial, we're going to fetch data from a REST API using the useEffect hook and update the local state using the useState Hook.

Edit ivstudio/react-useeffect-demo


useState Hook

The useState Hook lets us add local state to function components.

import React, { useState } from "react"

What does calling 'useState' do?

Calling useState declares a state variable. useState returns the current state value and a function that lets us update it. This a new way to use the exact same capabilities that this.state provides in a class component.

The only argument the useState() Hook takes is the initial state. Unlike with classes, the state doesn't have to be an object it could be a number, string, a function or whatever type we need.

In the next example, we declared a new state variable with the name of status and an initial value of loading. We can read the state directly using status and we can update the value by calling setStatus("new value").

const [status, setStatus] = useState("loading") if (status === "loading") { return <span>Loading...</span> }

useEffect Hook

In functional components we can use the useEffect hook to perform side effects. These are operations that affect our components and can't be done during rendering. Such as: fetching data, subscriptions or manually changing the DOM.

Data Fetching, setting up subscriptions, and manually changing the DOM in React are examples of side effects.

We can think of useEffect Hook as the lifecycle methods componentDidMount, componentDidUpdate, and componentWillUnmount combined from class components.

useEffect takes two arguments:

  1. Callback function
  2. Array of dependencies

By default, the useEffect Hook runs after every render, including the first one. When we use useEffect, we are telling React to do something after rendering.

If the dependencies array is empty it will only run once when the component mounts. If the dependencies array has values, useEffect will only run if any of those values change after the first render.

import React, { useState, useEffect } from "react" const [todos, setTodos] = useState([]) useEffect(() => { fetch("https://jsonplaceholder.typicode.com/posts") .then(response => response.json()) .then(data => setTodos(data)) }, []) // [] Array of dependencies and prevents unwanted re-renders.

Error handling

Let's update the Promise's resolution with async/await and use the try/catch statements to handle our response and update the setStatus accordingly.

import React, { useEffect, useState } from "react" import ReactDOM from "react-dom" function App() { const [todos, setTodos] = useState([]) const [status, setStatus] = useState("loading") const url = "https://jsonplaceholder.typicode.com/posts" useEffect(() => { async function fetchTodos() { try { const response = await fetch(url) if (!response.ok) { throw Error(`Error status ${response.status}`) } const data = await response.json() setTodos(data) setStatus("success") } catch (e) { setStatus("error") } } fetchTodos() }, []) if (status === "error") { return <div>Something went wrong...</div> } return ( <> {status === "loading" ? "loading..." : todos.map(todo => ( <div key={todo.id}> <h2>{todo.title}</h2> <p>{todo.body}</p> </div> ))} </> ) }

Edit ivstudio/react-useeffect-demo