Busque em todas as páginas da documentação
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
O middleware SWR envolve cada chamada useSWR, permitindo injetar preocupações transversais como logging, cabeçalhos de autenticação, tempo de requisição ou transformação de dados sem modificar hooks individuais.
"use client";
import { Middleware, SWRHook } from "swr";
const logger: Middleware = (useSWRNext: SWRHook) => {
return (key, fetcher, config) => {
const result = useSWRNext(key, fetcher, config);
if (result.error) {
console.error(`[SWR] ${key} erro:`, result.error);
} else if (result.data !== undefined) {
console.log(`[SWR] ${key} carregado:`, result.data);
}
return result;
};
};"use client";
import useSWR, { SWRConfig, Middleware, SWRHook } from "swr";
// ---- Middleware de Logging ----
const loggingMiddleware: Middleware = (useSWRNext: SWRHook) => {
return (key, fetcher, config) => {
const start = Date.now();
const result = useSWRNext(key, fetcher, config);
if (!result.isLoading && !result.isValidating) {
console.log(`[SWR] ${key} resolvido em ${Date.now() - start}ms`);
}
return result;
};
};
// ---- Middleware de Injeção de Autenticação ----
const authMiddleware: Middleware = (useSWRNext: SWRHook) => {
return (key, fetcher, config) => {
const wrappedFetcher = async (...args: any[]) => {
const token = localStorage.getItem("auth_token");
if (!token) throw new Error("Não autenticado");
// Se o fetcher for uma função, chame-o; caso contrário, use o padrão
if (typeof fetcher === "function") {
return fetcher(...args);
}
// Fetch padrão com cabeçalho de autenticação
const url = typeof key === "string" ? key : (key as any[])[0];
const res = await fetch(url, {
headers: { Authorization: `Bearer ${token}` },
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
};
return useSWRNext(key, wrappedFetcher, config);
};
};
// ---- Middleware de Transformação de Dados ----
const camelCaseMiddleware: Middleware = (useSWRNext: SWRHook) => {
return (key, fetcher, config) => {
const result = useSWRNext(key, fetcher, config);
return {
...result,
data: result.data ? toCamelCase(result.data) : result.data,
};
};
};
function toCamelCase(obj: any): any {
if (Array.isArray(obj)) return obj.map(toCamelCase);
if (obj && typeof obj === "object") {
return Object.fromEntries(
Object.entries(obj).map(([k, v]) => [
k.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),
toCamelCase(v),
])
);
}
return obj;
}
// ---- Aplicar Middleware ----
export default function App({ children }: { children: React.ReactNode }) {
return (
<SWRConfig
value={{
use: [loggingMiddleware, authMiddleware],
fetcher: (url: string) => fetch(url).then((r) => r.json()),
}}
>
{children}
</SWRConfig>
);
}
// ---- Uso (o middleware é executado automaticamente) ----
function Dashboard() {
const { data } = useSWR("/api/dashboard");
return <div>{JSON.stringify(data)}</div>;
}use, seja globalmente em SWRConfig ou por hook.useSWRNext, formando uma cadeia semelhante ao middleware do Express ou Redux.useSWR.Middleware por hook:
const { data } = useSWR("/api/special", fetcher, {
use: [specialMiddleware],
});Tentativa com middleware de backoff exponencial:
const retryMiddleware: Middleware = (useSWRNext) => {
return (key, fetcher, config) => {
return useSWRNext(key, fetcher, {
...config,
onErrorRetry: (error, _key, _config, revalidate, { retryCount }) => {
if (retryCount >= 3) return;
const delay = Math.min(1000 * 2 ** retryCount, 30000);
setTimeout(() => revalidate({ retryCount }), delay);
},
});
};
};Rastreador de deduplicação de requisição:
const dedupTracker: Middleware = (useSWRNext) => {
return (key, fetcher, config) => {
const result = useSWRNext(key, fetcher, config);
if (result.isValidating) {
performance.mark(`swr-start-${key}`);
} else {
performance.mark(`swr-end-${key}`);
performance.measure(`swr-${key}`, `swr-start-${key}`, `swr-end-${key}`);
}
return result;
};
};Middleware e SWRHook de swr para tipagem adequada.(useSWRNext: SWRHook) => SWRHook.SWRHook é (key, fetcher, config) => SWRResponse.import { Middleware, SWRHook, SWRResponse } from "swr";
const typedMiddleware: Middleware = (useSWRNext: SWRHook) => {
return <Data, Error>(
key: string,
fetcher: ((...args: any[]) => Promise<Data>) | null,
config: any
): SWRResponse<Data, Error> => {
return useSWRNext(key, fetcher, config);
};
};useSWR é ignorado. Certifique-se de chamar o original se você pretende envolvê-lo em vez de substituí-lo.useSWRNext condicionalmente dentro do middleware.use não substitui o middleware global; ele o estende. O middleware global é executado primeiro, seguido pelo middleware por hook.data no middleware cria uma nova referência de objeto em cada renderização, o que pode causar re-renderizações desnecessárias. Use memoização, se possível.| Abordagem | Prós | Contras |
|---|---|---|
| Middleware SWR | Componível, reutilizável, transparente | Assinaturas de tipo complexas, executa a cada renderização |
| Wrapper de fetcher customizado | Mais simples, explícito | Deve ser aplicado manualmente por fetcher |
| onSuccess/onError global | Embutido, sem necessidade de middleware | Limitado a eventos de sucesso e erro |
| Interceptadores Axios | Padrão familiar, nível de requisição/resposta | Vinculado ao axios, não ciente do SWR |
Middleware é um array de funções passado através da opção de configuração use. Cada um envolve useSWRNext, formando uma cadeia (como middleware do Express). O middleware pode modificar a chave, substituir o fetcher, alterar a configuração ou transformar o resultado retornado.
use: [middleware1, middleware2] em SWRConfig.use: [specialMiddleware] na configuração do hook.Sim. O primeiro middleware no array envolve o segundo, que envolve o terceiro, e assim por diante. O middleware de autenticação geralmente deve ser executado antes do middleware de logging para que os logs reflitam as requisições autenticadas.
Não. O middleware deve seguir as regras de hooks do React. Você não pode chamar useSWRNext condicionalmente - ele deve ser chamado em cada renderização, incondicionalmente.
Envolva o fetcher original em vez de substituí-lo:
const authMiddleware: Middleware = (useSWRNext) => {
return (key, fetcher, config) => {
const wrappedFetcher = async (...args: any[]) => {
// Adicione a lógica de autenticação aqui
if (typeof fetcher === "function") {
return fetcher(...args);
}
};
return useSWRNext(key, wrappedFetcher, config);
};
};Sim. Transformar data cria uma nova referência de objeto em cada renderização, o que pode acionar re-renderizações em componentes consumidores. Use memoização na transformação, se possível, para manter a estabilidade referencial.
import { Middleware, SWRHook } from "swr";
const myMiddleware: Middleware = (useSWRNext: SWRHook) => {
return (key, fetcher, config) => {
return useSWRNext(key, fetcher, config);
};
};A assinatura do middleware é (useSWRNext: SWRHook) => SWRHook.
Importe Middleware, SWRHook e, opcionalmente, SWRResponse de swr. Use esses tipos em vez de escrever a assinatura completa da função manualmente, pois as assinaturas são complexas.
O middleware é executado em cada renderização, não apenas quando os dados mudam. Mantenha o middleware leve e evite operações caras para prevenir degradação de desempenho.
Sim. Use o spread da configuração existente e substitua opções específicas:
const retryMiddleware: Middleware = (useSWRNext) => {
return (key, fetcher, config) => {
return useSWRNext(key, fetcher, {
...config,
errorRetryCount: 3,
});
};
};Revisado por Chris St. John·Última atualização: 7 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥