Skip to content
Documentação
Middleware

Middleware

💡

Atualize para a versão mais recente (≥ 1.0.0) para usar este recurso.

A funcionalidade de middleware é uma nova adição em SWR 1.0 que permite executar lógica antes e depois de executar os hooks SWR.

Uso

Middleware recebe o hook SWR e pode executar lógica antes e depois de rodá-lo. Se houver vários middleware, cada middleware embrulha o próximo middleware. O último middleware na lista receberá o hook SWR useSWR original.

API

Notas: O nome da função não pode ser capitalizado (exemplo: myMiddleware em vez de MyMiddleware) ou React lint irá lançar erro de Rules of Hook

TypeScript (opens in a new tab)

function myMiddleware (useSWRNext) {
  return (key, fetcher, config) => {
    // Antes do hook rodar...
 
    // Lida com o próximo middleware, ou o hook `useSWR` se este for o último.
    const swr = useSWRNext(key, fetcher, config)
 
    // Depois do hook rodar...
    return swr
  }
}

Você pode passar um array de middleware como uma opção para SWRConfig ou useSWR:

<SWRConfig value={{ use: [myMiddleware] }}>
 
// ou...
 
useSWR(key, fetcher, { use: [myMiddleware] })

Estendendo

Middleware será estendido como opções regulares. Por exemplo:

function Bar () {
  useSWR(key, fetcher, { use: [c] })
  // ...
}
 
function Foo() {
  return (
    <SWRConfig value={{ use: [a] }}>
      <SWRConfig value={{ use: [b] }}>
        <Bar/>
      </SWRConfig>
    </SWRConfig>
  )
}

é equivalente a:

useSWR(key, fetcher, { use: [a, b, c] })

Múltiplos Middleware

Cada middleware embrulha o próximo middleware, e o último embrulha o hook SWR. Por exemplo:

useSWR(key, fetcher, { use: [a, b, c] })

A ordem das execuções dos middlewares será a → b → c, como mostrado abaixo:

entra a
  entra b
    entra c
      useSWR()
    sai  c
  sai  b
sai  a

Exemplos

Request Logger

Vamos construir um middleware de request logger simples como exemplo. Ele imprime todos os requests feitos pelo fetcher enviado por este hook SWR. Você também pode usar este middleware para todos os hooks SWR usando ele em SWRConfig.

function logger(useSWRNext) {
  return (key, fetcher, config) => {
    // Adiciona o logger ao fetcher original.
    const extendedFetcher = (...args) => {
      console.log('SWR Request:', key)
      return fetcher(...args)
    }
 
    // Executa o hook com o novo fetcher.
    return useSWRNext(key, extendedFetcher, config)
  }
}
 
// ... dentro do seu componente
useSWR(key, fetcher, { use: [logger] })

Toda vez que o pedido é disparado, ele imprime a chave SWR para o console:

SWR Request: /api/user1
SWR Request: /api/user2

Manter Resultado Anterior

As vezes você quer que os dados retornados por useSWR sejam "lentos". Mesmo se a chave mudar, você ainda quer que ele retorne o resultado anterior até que os novos dados tenham carregado.

Isso pode ser construído como um middleware "lento" junto com useRef. Nesse exemplo, também vamos estender o objeto de retorno do hook useSWR:

import { useRef, useEffect, useCallback } from 'react'
 
// Esse é um middleware SWR para manter os dados mesmo se a chave muda.
function laggy(useSWRNext) {
  return (key, fetcher, config) => {
    // Use uma ref para armazenar os dados retornados anteriormente.
    const laggyDataRef = useRef()
 
    // O hook SWR.
    const swr = useSWRNext(key, fetcher, config)
 
    useEffect(() => {
      // Atualize a ref se o dado não é `undefined`.
      if (swr.data !== undefined) {
        laggyDataRef.current = swr.data
      }
    }, [swr.data])
 
    // Expor um método para limpar os dados lentos, se houver.
    const resetLaggy = useCallback(() => {
      laggyDataRef.current = undefined
    }, [])
 
    // Fallback para os dados anteriores se o dado atual é `undefined`.
    const dataOrLaggyData = swr.data === undefined ? laggyDataRef.current : swr.data
 
    // Está mostrando dados antigos?
    const isLagging = swr.data === undefined && laggyDataRef.current !== undefined
 
    // Também adiciona um campo `isLagging` para SWR;
    return Object.assign({}, swr, {
      data: dataOrLaggyData,
      isLagging,
      resetLaggy,
    })
  }
}

Quando você precisa que um hook SWR seja lento, você pode então usar este middleware:

const { data, isLagging, resetLaggy } = useSWR(key, fetcher, { use: [laggy] })

Serializar Chaves de Objeto

💡

Desde SWR 1.1.0, os keys de objetos serão serializados automaticamente.

⚠️

Em versões antigas (< 1.1.0), SWR compara os argumentos superficialmente em cada renderização e aciona a revalidação se algum deles foi alterado.

Se você está passando objetos serializados como chave, você pode serializar as chaves de objetos para garantir sua estabilidade, um simples middleware pode ajudar:

function serialize(useSWRNext) {
  return (key, fetcher, config) => {
    // Serializa a chave.
    const serializedKey = Array.isArray(key) ? JSON.stringify(key) : key
 
    // Passa a chave serializada e deserializa no fetcher.
    return useSWRNext(serializedKey, (k) => fetcher(...JSON.parse(k)), config)
  }
}
 
// ...
useSWR(['/api/user', { id: '73' }], fetcher, { use: [serialize] })
 
// ... ou habilite isto globalmente com
<SWRConfig value={{ use: [serialize] }}>

Você não precisa de preocupar com objetos que podem mudar entre renderizações. Ele será serializado para uma mesma string, e o fetcher irá receber os argumentos de objetos.

💡

Além disso, você pode usar bibliotecas como fast-json-stable-stringify (opens in a new tab) em vez de JSON.stringify — mais rápido e estável.