import { Callout } from 'nextra-theme-docs'
Обновитесь до последней версии (≥ 1.0.0), чтобы использовать этот функционал.Функционал ППО — это новое дополнение в SWR 1.0, которое позволяет вам выполнять логику до и после SWR хуков.
Промежуточное ПО получает SWR хук и может выполнять логику до и после его запуска. Если ППО несколько, каждый ППО оборачивает последующий. Последний ППО в списке получит исходный хук SWR — useSWR
.
Примечание: Имя функции не должно быть написано с заглавной буквы (например, myMiddleware
вместо MyMiddleware
), иначе правила линтера React будут выдавать ошибку Rules of Hook
function myMiddleware (useSWRNext) {
return (key, fetcher, config) => {
// До выполнения хука...
// Обработка следующего ППО, или хука `useSWR`, если это последнее.
const swr = useSWRNext(key, fetcher, config)
// После выполнения хука...
return swr
}
}
Вы можете передать массив из нескольких ППО как опцию SWRConfig
или useSWR
:
<SWRConfig value={{ use: [myMiddleware] }}>
// или...
useSWR(key, fetcher, { use: [myMiddleware] })
Промежуточное ПО расширяется как обычные опции. Например:
function Bar () {
useSWR(key, fetcher, { use: [c] })
// ...
}
function Foo() {
return (
<SWRConfig value={{ use: [a] }}>
<SWRConfig value={{ use: [b] }}>
<Bar/>
</SWRConfig>
</SWRConfig>
)
}
эквивалентно:
useSWR(key, fetcher, { use: [a, b, c] })
Каждое ППО обворачивает последующее, а последнее ППО обворачивает SWR хук. Например:
useSWR(key, fetcher, { use: [a, b, c] })
Порядок выполнения ППО будет a → b → c
, как показано ниже:
вход в a
вход в b
вход в c
useSWR()
выход из c
выход из b
выход из a
Давайте в качестве примера создадим простой ППО — регистратора запросов. Он выводит все запросы fetcher-а, отправленные с этого хука SWR. Вы также можете использовать этот ППО для всех хуков SWR, добавив его в SWRConfig
.
function logger(useSWRNext) {
return (key, fetcher, config) => {
// Добавим регистратор в исходный fetcher.
const extendedFetcher = (...args) => {
console.log('SWR запрос:', key)
return fetcher(...args)
}
// Выполняем хук с новым fetcher-ом.
return useSWRNext(key, extendedFetcher, config)
}
}
// ... внутри вашего компонента
useSWR(key, fetcher, { use: [logger] })
Каждый раз, когда запрос запускается, он выводит ключ SWR в консоль:
SWR запрос: /api/user1
SWR запрос: /api/user2
Иногда вы хотите, чтобы данные, возвращаемые useSWR
, были «запаздывающими». Даже если ключ изменится, вы все равно хотите, чтобы он возвращал предыдущий результат, пока не загрузятся новые данные.
Это может быть построено как замедленное ППО используя useRef
. В этом примере мы также собираемся расширить возвращаемый объект хука useSWR
:
import { useRef, useEffect, useCallback } from 'react'
// Это ППО SWR для хранения данных даже при изменении ключа.
function laggy(useSWRNext) {
return (key, fetcher, config) => {
// Используйте ссылку для хранения ранее возвращённых данных.
const laggyDataRef = useRef()
// Фактический хук SWR.
const swr = useSWRNext(key, fetcher, config)
useEffect(() => {
// Обновите ссылку если данные определены.
if (swr.data !== undefined) {
laggyDataRef.current = swr.data
}
}, [swr.data])
// Предоставьте метод очистки запаздывающих данных, если таковые имеются.
const resetLaggy = useCallback(() => {
laggyDataRef.current = undefined
}, [])
// Возврат к предыдущим данным, если текущие данные не определены.
const dataOrLaggyData = swr.data === undefined ? laggyDataRef.current : swr.data
// Показывает предыдущие данные?
const isLagging = swr.data === undefined && laggyDataRef.current !== undefined
// Также добавьте поле `isLagging` в SWR.
return Object.assign({}, swr, {
data: dataOrLaggyData,
isLagging,
resetLaggy,
})
}
}
Когда вам нужно, чтобы хук SWR работал с задержкой, вы можете использовать это ППО:
const { data, isLagging, resetLaggy } = useSWR(key, fetcher, { use: [laggy] })
function serialize(useSWRNext) {
return (key, fetcher, config) => {
// Сериализуйте ключ.
const serializedKey = Array.isArray(key) ? JSON.stringify(key) : key
// Передайте сериализованный ключ и десериализуйте его в fetcher-е.
return useSWRNext(serializedKey, (k) => fetcher(...JSON.parse(k)), config)
}
}
// ...
useSWR(['/api/user', { id: '73' }], fetcher, { use: [serialize] })
// ... или включите его глобально с помощью
<SWRConfig value={{ use: [serialize] }}>
Вам не нужно беспокоиться о том, что объект может измениться между рендерами. Он всегда сериализуется в одну и ту же строку, и fetcher по-прежнему получит эти аргументы объекта.
Кроме того, вы можете использовать такие библиотеки, как [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) вместо `JSON.stringify` — быстрее и стабильнее.