Промежуточное программное обеспечение (ППО) (Middleware)
Обновитесь до последней версии (≥ 1.0.0), чтобы использовать этот функционал.
Функционал ППО — это новое дополнение в SWR 1.0, которое позволяет вам выполнять логику до и после SWR хуков.
Использование
Промежуточное ПО получает SWR хук и может выполнять логику до и после его запуска. Если ППО несколько, каждый ППО оборачивает последующий. Последний ППО в списке получит исходный хук SWR — useSWR
.
API
Примечание: Имя функции не должно быть написано с заглавной буквы (например, myMiddleware
вместо MyMiddleware
), иначе правила линтера React будут выдавать ошибку Rules of Hook
TypeScript (opens in a new tab)
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] })
Сериализация ключей объекта
Начиная с версии SWR 1.1.0 объектно-подобные ключи будут автоматически сериализоваться «из коробки».
В более старых версиях (< 1.1.0) SWR поверхностно сравнивает аргументы при каждом рендеринге и запускает повторную проверку, если какой-либо из них изменился. Если вы передаете сериализуемые объекты в качестве ключа. Вы можете сериализовать ключи объекта, чтобы обеспечить его стабильность, может помочь простое промежуточное ПО:
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 (opens in a new tab) вместо JSON.stringify
— быстрее и стабильнее.