4 KiB
title | date | draft | tags | |||||
---|---|---|---|---|---|---|---|---|
Simple data fetching with custom React hooks and SWR | 2022-05-23 | false |
|
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 5861. SWR 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.
-
For the request to oku, I've configured a rewrite in
next.config.js
; for last.fm I've added a simpleapi/music.ts
route that interpolates my private API key stored in my Vercel environment variables. ↩︎ -
The full
reading.tsx
implementation can be viewed here. ↩︎ -
The full
music.tsx
implementation can be viewed here. ↩︎