This repository has been archived on 2025-03-28. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
coryd.dev-eleventy/src/posts/2022/simple-api-fetch-hooks-with-swr.md

4 KiB

title date draft tags
Simple data fetching with custom React hooks and SWR 2022-05-23 false
SWR
API
fetch
React
Next.js

My site was scaffolded out using Timothy Lin's tailwind-nextjs-starter-blog project (which I highly recommend checking out). As part of the build out I wanted to display the books I'm currently reading and the song I most recently listened to, data available from oku and Last.fm, respectively.1 I've added the display for this data to the top of the home page using a pair of light-weight React components.

To fetch the data for these components I elected to leverage vercel/swr, described as:

SWR is a React Hooks library for data fetching.

The name "SWR" is derived from stale-while-revalidate, a cache invalidation strategy popularized by HTTP RFC 5861SWR first returns the data from cache (stale), then sends the request (revalidate), and finally comes with the up-to-date data again.

On oku, each collection page contains an RSS feed exposing the data for that page. To retrieve and parse the data for my reading collection, I'm leveraging feed-reader and passing it to the useSWR hook exposed by swr. This looks like the following:

import { read } from 'feed-reader'
import { useEffect, useState } from 'react'
import useSWR from 'swr'

export const useRss = (url: string) => {
  const [response, setResponse] = useState([])

  const fetcher = (url: string) =>
    read(url)
      .then((res) => res.entries)
      .catch()
  const { data, error } = useSWR(url, fetcher)

  useEffect(() => {
    setResponse(data)
  }, [data, setResponse])

  return {
    response,
    error,
  }
}

This is then implemented in a reading.tsx component as follows2:

const { response, error } = useRss('/books')

Similarly, I've implemented a hook to fetch json using, well, fetch and that looks like the following:

import { useEffect, useState } from 'react'
import useSWR from 'swr'

export const useJson = (url: string) => {
  const [response, setResponse] = useState<any>({})

  const fetcher = (url: string) =>
    fetch(url)
      .then((res) => res.json())
      .catch()
  const { data, error } = useSWR(url, fetcher)

  useEffect(() => {
    setResponse(data)
  }, [data, setResponse])

  return {
    response,
    error,
  }
}

This is then implemented in a music.tsx component as follows3:

const { response, error } = useJson('/api/music')

The useJson hook only supports GET requests at this point but, could, with a little effort, be refactored to support parameters passed through to the enclosed fetch call. This could be done by updating the interface to accept a parameters object that includes the url to be called or by adding a separate, optional parameters object. I would lean towards the latter approach as the usage would only become as complex as a specific implementation requires.

Both of these components are visible at coryd.dev. The loading state is displayed until response is valid and null is returned in the event an error occurs as returned by the hook.


  1. For the request to oku, I've configured a rewrite in next.config.js; for last.fm I've added a simple api/music.ts route that interpolates my private API key stored in my Vercel environment variables. ↩︎

  2. The full reading.tsx implementation can be viewed here. ↩︎

  3. The full music.tsx implementation can be viewed here. ↩︎