SWR

is a hook for data fetching that provides caching, revalidation, and mutation capabilities. It's designed to make data fetching simple and efficient by automatically handling loading states, error handling, and cache management.

Inspired by Vercel's SWR, it follows the stale-while-revalidate pattern, serving cached data while fetching fresh data in the background.

takes a key and a fetcher function, and returns an object containing:

  • data: The fetched data (null if not loaded)
  • loading: Boolean indicating if the initial request is pending
  • error: Error object if the request failed
  • mutate: Function to trigger mutations and update the cache
  • isMutating: Signal indicating if a mutation is in progress
  • isValidating: Signal indicating if revalidation is happening
import { useSWR } from "kiru/swr"

interface User {
  id: number
  name: string
  email: string
}

const fetcher = async (url: string): Promise<User> => {
  const res = await fetch(url)
  if (!res.ok) throw new Error("Failed to fetch")
  return res.json()
}

function UserProfile({ userId }: { userId: number }) {
  const { data, loading, error } = useSWR(`/api/users/${userId}`, fetcher)

  if (loading) return <div>Loading...</div>
  if (error) return <div>Error: {error.message}</div>

  return (
    <div>
      <h2>{data.name}</h2>
      <p>{data.email}</p>
    </div>
  )
}

The mutate function allows you to update data and trigger revalidation. It accepts a function that returns a Promise, and the cache will be updated with the resolved value.

import { useSWR } from "kiru/swr"

interface User {
  id: number
  name: string
  email: string
}

const fetcher = async (url: string): Promise<User> => {
  const res = await fetch(url)
  if (!res.ok) throw new Error("Failed to fetch")
  return res.json()
}

function EditableUserProfile({ userId }: { userId: number }) {
  const { data, loading, error, mutate, isMutating } = useSWR(
    `/api/users/${userId}`,
    fetcher
  )

  const updateUser = async (newName: string): Promise<User> => {
    const res = await fetch(`/api/users/${userId}`, {
      method: "PUT",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ name: newName }),
    })
    return res.json()
  }

  if (loading) return <div>Loading...</div>
  if (error) return <div>Error: {error.message}</div>

  return (
    <div>
      <input
        value={data.name}
        onchange={(e) => mutate(() => updateUser(e.target.value))}
        disabled={isMutating.value}
      />
      {isMutating.value && <span>Saving...</span>}
    </div>
  )
}

Multiple components using the same key will share the same data and only trigger one network request. The cache is automatically managed and data is revalidated when components mount or when the window regains focus.

Related