SWR Documentation

repository·main·Indexed 19 days ago

https://github.com/vercel/swr-site

Official documentation for the SWR library, including guides on using fallback data for SSG/SSR, implementing SWR middleware, and utilizing useSWRImmutable for static resources. Includes detailed migration paths from SWR 0.x to 1.0, covering breaking changes such as the renaming of initialData to fallbackData, the replacement of revalidate with mutate, the removal of the default fetcher, and updated TypeScript type definitions.

Tokens
120.1K
Snippets
397
Records
498
Agent score
57%

What's inside SWR

  1. What is a Cache Provider in SWR

    main

    By default, SWR uses a global cache to store and share data across components. A Cache Provider allows you to customize this behavior by providing a custom storage mechanism (e.g., localStorage, IndexedDB).

    A Cache Provider must be a Map-like object that implements the following Cache<Data> interface:

    interface Cache<Data> {
      get(key: string): Data | undefined
      set(key: string, value: Data): void
      delete(key: string): void
      keys(): IterableIterator<string>
    }

    For example, a standard JavaScript Map instance satisfies this interface and can be used directly.

  2. Handle changes to Cache internal structure in SWR v2

    main

    The internal structure of the cache has changed. The cache now stores an object containing the current state (data, error, and isValidating) for each key, rather than just the data itself.

    Warning: Do not write to the cache directly, as this may cause undefined behavior.

    // Internal structure change
    - assert(cache.get(key) === data)
    + assert(cache.get(key) === { data, error, isValidating })
    
    // Getter usage
    - cache.get(key)
    + cache.get(key)?.data
    
    // Setter usage
    - cache.set(key, data)
    + cache.set(key, { ...cache.get(key), data })
  3. How SWR optimizes re-renders with deep comparison

    main

    By default, SWR performs a deep comparison on the data returned by the hook. If the new data is structurally identical to the previous data, SWR will not trigger a re-render of your component.

    If you need to customize this behavior (for example, to ignore specific fields like server timestamps that change on every request), you can provide a custom comparison function using the compare option.

  4. Migration Guide: Internal Cache structure changes

    main

    The internal structure of the cache has changed. Instead of storing the raw data, the cache now stores an object containing the current states.

    Warning: Do not write to the cache directly, as this can cause undefined behavior.

    • Getter: Use cache.get(key)?.data to access the data.
    • Setter: Use cache.set(key, { ...cache.get(key), data }) to update data.
    - assert(cache.get(key) === data)
    + assert(cache.get(key) === { data, error, isValidating })
    
    // getter
    - cache.get(key)
    + cache.get(key)?.data
    
    // setter
    - cache.set(key, data)
    + cache.set(key, { ...cache.get(key), data })
  5. How SWR handles data binding and deduplication

    main

    SWR allows you to bind data directly to the components that need it. This solves the problem of 'prop drilling' (passing data through many layers of components) and the limitations of React Context when dealing with dynamic content.

    Key Benefits:

    • Decoupling: Parent components do not need to know about the data requirements of their children; they simply render them.
    • Deduplication: If multiple components use the same SWR key (e.g., the same API URL), SWR sends only one request to the API.
    • Caching & Sharing: Data is automatically cached and shared across components using the same key.
    • Automatic Revalidation: SWR automatically refreshes data when the user refocuses the window or reconnects to the network.
  6. How SWR improves component architecture

    main

    SWR allows you to move away from the 'prop drilling' pattern where data is fetched at a top-level component and passed down through multiple layers.

    By using SWR (or custom hooks built on top of it) inside the specific components that need the data, you achieve several benefits:

    1. Decoupling: Components become independent and don't need to know about the data requirements of their children.
    2. Efficiency: If multiple components use the same SWR key (e.g., the same API URL), SWR automatically deduplicates the requests, sending only one network request and sharing the cached result.
    3. Automatic Revalidation: Data is automatically updated on focus or network reconnection.

    Comparison:

    • Traditional approach: Fetch in Page component $\rightarrow$ pass user via props to Navbar $\rightarrow$ pass user via props to Avatar.
    • SWR approach: Page renders children $\rightarrow$ Avatar calls useUser(id) directly.
    // Component-level data binding with SWR
    function Content ({ userId }) {
      const { user, isLoading } = useUser(userId)
      if (isLoading) return <Spinner />
      return <h1>Welcome back, {user.name}</h1>
    }
    
    function Avatar ({ userId }) {
      const { user, isLoading } = useUser(userId)
      if (isLoading) return <Spinner />
      return <img src={user.avatar} alt={user.name} />
    }
  7. Behavior of `data` with conditional fetching in Suspense mode

    main

    While data is typically guaranteed to be ready when using suspense: true, it will be undefined if you are using conditional fetching or dependent fetching and the request is currently paused.

    For example, if the key passed to useSWR is null (e.g., isReady ? '/api/user' : null), data will be undefined while isReady is false.

    function Profile () {
      const { data } = useSWR(isReady ? '/api/user' : null, fetcher, { suspense: true })
    
      // `data` will be `undefined` if `isReady` is false
      // ...
    }
  8. Understand the new Cache internal structure

    main

    The internal structure of the SWR cache has changed. The cache now stores an object containing the current state (data, error, and isValidating) for each key, rather than just the data itself.

    Warning: Do not write to the cache directly, as this may cause undefined behavior.

    - assert(cache.get(key) === data)
    + assert(cache.get(key) === { data, error, isValidating })
    
    // getter
    - cache.get(key)
    + cache.get(key)?.data
    
    // setter
    - cache.set(key, data)
    + cache.set(key, { ...cache.get(key), data })
  9. Control revalidation on mount

    main

    You can control how SWR behaves when a hook is first mounted using the revalidateOnMount and revalidateIfStale options.

    revalidateOnMount

    • If true: SWR starts a request immediately upon mounting.
    • If false: SWR stops the request upon mounting.
    • If undefined (default): SWR follows its default internal logic.

    revalidateIfStale

    This option controls whether SWR should re-fetch data if stale data is already present in the cache.

    • If true (default): SWR re-fetches if cached data exists. If no cached data exists, it fetches.
    • If false: SWR will not re-fetch if stale data is present.