1. Введение
Выборка — важная часть фронтенд-бизнеса, и она претерпела несколько изменений:
-
fetchСовместимость была достаточно хорошей, чтобы заменить включить
$.post
Различные пакеты извлечения, в том числе. - Он изначально использовался в течение длительного времени, и было обнаружено, что расширение лучше, и схема изоморфной выборки, поддерживающая ssr, также очень хороша, напримерisomorphic-fetch,axios.
- Для сценариев, управляемых данными, этого все еще недостаточно: поток данных постепенно инкапсулирует выборку данных, и в то же время осуществляется управление изменением состояния на основе данных.
data
isLoading
error
упаковка. - Появление хуков делает компоненты более реактивными, и мы обнаружили, что выборка изящно возвращается к компонентам,swrЭто пример из учебника.
swrПредставлено 29.10.2019, всего за 12 дней было сохранено более 4000 звезд, в среднем 300+ звезд в день! Интенсивное чтение на этой неделе будет посвящено анализу функций и исходного кода этой библиотеки, а также пониманию того, почему, как и что в этой библиотеке извлечения React Hooks.
2 Обзор
Сначала введите функцию swr.
Чтобы отличаться от официальной документации, автор представляет ее в ознакомительном ключе, но все примеры взяты из официальной документации.
2.1 Зачем использовать хуки для получения чисел
Сначала ответьте на фундаментальный вопрос: зачем использовать хуки вместо выборки или потоковой выборки?
потому чтоХуки могут достигать жизненного цикла пользовательского интерфейса, а выборка — это, по сути, часть отображения пользовательского интерфейса или взаимодействия.Форма взятия чисел с помощью Hooks следующая:
import useSWR from "swr";
function Profile() {
const { data, error } = useSWR("/api/user", fetcher);
if (error) return <div>failed to load</div>;
if (!data) return <div>loading...</div>;
return <div>hello {data.name}!</div>;
}
Первое, что вы видите, это то, что асинхронная логика описана в синхронной записи, потому что рендеринг выполняется дважды.
useSWR
Получите три параметра, первый параметр - числоkey
,этоkey
как второй параметрfetcher
Первый параметр передается, в обычных сценариях это URL-адрес, а третий параметр — элемент конфигурации.
Сила хуков заключается не только в этом, приведенные выше короткие строки кода также имеют следующие функции:
- Обновляется автоматически.
- Когда компонент уничтожается и повторно визуализируется, сначала включается локальный кеш.
- Положение полосы прокрутки может автоматически запоминаться при откате браузера на странице списка.
- Когда вкладки переключаются, сфокусированная вкладка будет повторно выбрана.
Конечно, автоматическое обновление или повторная загрузка — это не обязательно то, что нам нужно.swrРазрешить пользовательские конфигурации.
2.2 Конфигурация
упомянутый выше,useSWR
Существует также третий параметр в качестве элемента конфигурации.
Автономная конфигурация
Передайте третий параметр для каждогоuseSWR
Автономная конфигурация:
useSWR("/api/user", fetcher, { revalidateOnFocus: false });
Элементы конфигурации могут относиться кДокументация.
Можно настроить следующие параметры: режим приостановки, повторная выборка фокуса, интервал повторной выборки/открытия, необходимость повторной выборки при сбое, время ожидания, функция обратного вызова при успешной/неудачной выборке/повторной попытке и т. д.
Если второй параметр имеет тип объекта, то эффект является элементом конфигурации.Второй сборщик предоставлен только для удобства.Выборщик также может быть настроен в элементе конфигурации объекта.
Глобальная конфигурация
SWRConfig
Конфигурация может быть изменена в пакетном режиме:
import useSWR, { SWRConfig } from "swr";
function Dashboard() {
const { data: events } = useSWR("/api/events");
// ...
}
function App() {
return (
<SWRConfig value={{ refreshInterval: 3000 }}>
<Dashboard />
</SWRConfig>
);
}
Независимая конфигурация имеет более высокий приоритет, чем глобальная конфигурация, и метод реализации будет представлен в разделе интенсивного чтения.
Самый тяжелый элемент конфигурацииfetcher
, который определяет способ получения числа.
2.3 Пользовательский метод получения
Пользовательская логика выборки фактически разделена на несколько абстрактных элементов, таких как настраиваемый URL-адрес выборки или настройка всей функции выборки, в то время какswrПринята относительно промежуточная степень детализации настройкиfetcher
:
import fetch from "unfetch";
const fetcher = url => fetch(url).then(r => r.json());
function App() {
const { data } = useSWR("/api/data", fetcher);
// ...
}
такfetcher
Это точка расширения сама по себе, мы можем не только настроить функцию выборки номера, настроить логику бизнес-процессинга, но даже настроить протокол выборки номера:
import { request } from "graphql-request";
const API = "https://api.graph.cool/simple/v1/movies";
const fetcher = query => request(API, query);
function App() {
const { data, error } = useSWR(
`{
Movie(title: "Inception") {
releaseDate
actors {
name
}
}
}`,
fetcher
);
// ...
}
Это соответствует причине, по которой первый параметр называется Key, который является описанием синтаксиса в graphql.
На этом этапе мы можем настроить функцию выборки, но мы не можем контролировать, когда выполнять выборку, потому что метод записи хуков объединяет время выборки с временем рендеринга.swrМеханизм условного доступа может решить эту проблему.
2.4 Условный доступ
Так называемое условное число, т.useSWR
Когда первый параметр равен нулю, выборка будет прекращена Мы можем использовать тернарный оператор или функцию в качестве первого параметра, чтобы сделать это условие динамическим:
// conditionally fetch
const { data } = useSWR(shouldFetch ? "/api/data" : null, fetcher);
// ...or return a falsy value
const { data } = useSWR(() => (shouldFetch ? "/api/data" : null), fetcher);
В приведенном выше примере, когдаshouldFetch
При значении false номер не будет получен.
Первый параметр выборки рекомендуется использовать в качестве функции обратного вызова, чтобыswrБудет поймать внутреннее исключение, например:
// ... or throw an error when user.id is not defined
const { data, error } = useSWR(() => "/api/data?uid=" + user.id, fetcher);
еслиuser
объект не существует,user.id
потерпит неудачу, и ошибка будет перехвачена и переданаerror
объект.
Фактически,user.id
Это также сценарий зависимой выборки, когдаuser.id
Его необходимо повторно получить, когда есть изменение.
2.5 Зависимая выборка
Если одна выборка зависит от результата другой выборки, то новая выборка будет запущена только тогда, когда закончатся первые данные, чтоswrОсобого внимания на это обращать не нужно, просто напишите в порядке зависимостиuseSWR
Только что:
function MyProjects() {
const { data: user } = useSWR("/api/user");
const { data: projects } = useSWR(() => "/api/projects?uid=" + user.id);
if (!projects) return "loading...";
return "You have " + projects.length + " projects";
}
swrЗапросы без зависимостей будут максимально распараллелены, а выборки с зависимостями будут отправляться по одному в порядке зависимости.
Вполне возможно, что при ручном управлении выборкой, когда зависимости сложные, для обеспечения максимального параллелизма выборки часто необходимо тщательно настраивать рекурсивную структуру вложенности выборки.swrВ этой среде вам нужно только писать последовательно, что значительно повышает эффективность. Метод оптимизации подробно описан в разделе интерпретации исходного кода ниже.
Зависимая выборка — это сценарий, в котором выборка автоматически перезапускается.swrРучной запуск повторной загрузки также поддерживается.
2.6 Ручная выборка триггера
trigger
Извлечение может быть запущено вручную с помощью ключа:
import useSWR, { trigger } from "swr";
function App() {
return (
<div>
<Profile />
<button
onClick={() => {
// set the cookie as expired
document.cookie =
"token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
// tell all SWRs with this key to revalidate
trigger("/api/user");
}}
>
Logout
</button>
</div>
);
}
Большинство сценариев не должны быть такими,Поскольку повторный запуск запроса определяется данными и зависимостями, но необходимость выборки определяется не параметрами выборки, а когда требуется время, требуется возможность ручной выборки.
2.7 Оптимистичная выборка
Особенно в сценарии формы изменения данных предсказуемы. В настоящее время решение, управляемое данными, может только ждать, пока серверная часть вернет результат. Фактически, его можно оптимизировать для локального изменения данных, а затем обновить их после возвращается результат бэкенда:
import useSWR, { mutate } from "swr";
function Profile() {
const { data } = useSWR("/api/user", fetcher);
return (
<div>
<h1>My name is {data.name}.</h1>
<button
onClick={async () => {
const newName = data.name.toUpperCase();
// send a request to the API to update the data
await requestUpdateUsername(newName);
// update the local data immediately and revalidate (refetch)
mutate("/api/user", { ...data, name: newName });
}}
>
Uppercase my name!
</button>
</div>
);
}
пройти черезmutate
Вы можете временно изменить ключ локально и вернуть результат, особенно в случае плохой сетевой среды, чтобы ускорить ответ. Оптимистичная выборка означает, что результат выборки является оптимистичным и предсказуемым, поэтому результат можно предсказать и изменить до того, как результат будет возвращен.
2.8 Режим ожидания
В режиме React Suspense все подмодули могут быть загружены лениво, включая код и запросы, которые можно ожидать, пока он включен.suspense
свойства могут быть:
import { Suspense } from "react";
import useSWR from "swr";
function Profile() {
const { data } = useSWR("/api/user", fetcher, { suspense: true });
return <div>hello, {data.name}</div>;
}
function App() {
return (
<Suspense fallback={<div>loading...</div>}>
<Profile />
</Suspense>
);
}
2.9 Обработка ошибок
onErrorRetry
Ошибки могут обрабатываться единообразно, включая повторную выборку после возникновения ошибки и т. д.:
useSWR(key, fetcher, {
onErrorRetry: (error, key, option, revalidate, { retryCount }) => {
if (retryCount >= 10) return;
if (error.status === 404) return;
// retry after 5 seconds
setTimeout(() => revalidate({ retryCount: retryCount + 1 }), 5000);
}
});
- локальная мутация
- suspense mode
- обработка ошибок
// conditionally fetch
const { data } = useSWR(shouldFetch ? "/api/data" : null, fetcher);
// ...or return a falsy value
const { data } = useSWR(() => (shouldFetch ? "/api/data" : null), fetcher);
// ... or throw an error when user.id is not defined
const { data } = useSWR(() => "/api/data?uid=" + user.id, fetcher);
3 Интенсивное чтение
3.1 Глобальная конфигурация
В сценарии Hooks оберните слой настройкиContext
Глобальная конфигурация может быть достигнута.
первыйSWRConfig
По сути обычайContext Provider
:
const SWRConfig = SWRConfigContext.Provider;
существуетuseSWR
Объедините текущую конфигурацию с глобальной конфигурацией вuseContext
Получите глобальную конфигурацию:
config = Object.assign({}, defaultConfig, useContext(SWRConfigContext), config);
3.2 Некоторые детали использования SWR
Вы можете увидеть более подробную информацию из исходного кода,useSWR
Действительно лучше, чем вызывать вручнуюfetch
намного лучше.
совместимость
useSWR
код тела вuseEffect
, но чтобы ускорить время запроса, он помещается перед отрисовкой пользовательского интерфейса (useLayoutEffect
) и совместим со сценариями на стороне сервера:
const useIsomorphicLayoutEffect = IS_SERVER ? useEffect : useLayoutEffect;
неблокирующий
Время запроса — это когда браузер бездействует, поэтому вызывается функция запроса.requestIdleCallback
пакет:
window["requestIdleCallback"](softRevalidate);
softRevalidate
дедупликация включенаrevalidate
:
const softRevalidate = () => revalidate({ dedupe: true });
То есть повторные выборки с одними и теми же параметрами в течение 2 секунд по умолчанию будут отменены.
оптимизация производительности
из-заswrизdata
,isValidating
и т. д. состояние данных используетсяuseState
Отдельно управляются:
let [data, setData] = useState(
(shouldReadCache ? cacheGet(key) : undefined) || config.initialData
);
// ...
let [isValidating, setIsValidating] = useState(false);
Когда состояние выборки изменяется, частоdata
а такжеisValidating
Чтобы обновить вместе, чтобы вызвать только одно обновление, используйтеunstable_batchedUpdates
Объедините обновления в одно:
unstable_batchedUpdates(() => {
setIsValidating(false);
// ...
setData(newData);
});
На самом деле есть и другие решения, такие как использованиеuseReducer
Управление данными также может обеспечить такой же эффект производительности.
3.3 Начальный кеш
При переключении страницы можно временно заменить результат выборки последними данными, то есть данные инициализации берутся из кеша:
const shouldReadCache = config.suspense || !useHydration();
// stale: get from cache
let [data, setData] = useState(
(shouldReadCache ? cacheGet(key) : undefined) || config.initialData
);
Приведенный выше код находится вuseSWR
Во время инициализацииuseHydration
Указывает, является ли это первой загрузкой:
let isHydration = true;
export default function useHydration(): boolean {
useEffect(() => {
setTimeout(() => {
isHydration = false;
}, 1);
}, []);
return isHydration;
}
3.4 Поддержка саспенса
Приостановка разделена на две функции: асинхронная загрузка кода и асинхронная загрузка данных, и теперь упоминается возможность асинхронной загрузки данных.
Приостановка требует, чтобы код был приостановлен, то есть генерировалось перехватываемое исключение Promise и отрисовывался компонент после завершения Promise.
Основным кодом является этот раздел, бросающий обещание числа:
throw CONCURRENT_PROMISES[key];
Подождите, пока номер не будет завершен, а затем вернитесьuseSWR
Структура, определяемая API:
return {
error: latestError,
data: latestData,
revalidate,
isValidating
};
без вышеперечисленногоthrow
шаг, компонент будет отображаться до завершения выборки, поэтомуthrow
Обещание запроса делает эту функцию запроса способной к приостановке.
3.5 Зависимые запросы
Я просмотрел код и не нашел логики для специальной обработки циклических зависимостей.Позже, прочитав официальный документ, я вдруг понял, что он оказался черезtry/catch
+ onErrorRetry
Реализация механизма зависит от выборки.
Посмотрите на следующий код:
const { data: user } = useSWR("/api/user");
const { data: projects } = useSWR(() => "/api/projects?uid=" + user.id);
Как добиться интеллектуального запроса в порядке зависимости? мы видимuseSWR
Основная логика функции выборки:
try {
// 设置 isValidation 为 true
// 取数、onSuccess 回调
// 设置 isValidation 为 false
// 设置缓存
// unstable_batchedUpdates
} catch (err) {
// 撤销取数、缓存等对象
// 调用 onErrorRetry
}
Можно видеть, что логика выборкиtry
живи, тогдаuser.id
существуетuseSWR("/api/user")
Если Готово нет, будет выброшено исключение, и оно автоматически войдетonErrorRetry
Логика, посмотрите в следующий раз, когда номер будет выбранuser.id
Готового нет.
Так когда будет следующая очередь считать? Время:
const count = Math.min(opts.retryCount || 0, 8);
const timeout =
~~((Math.random() + 0.5) * (1 << count)) * config.errorRetryInterval;
Время повтора в основном растет экспоненциально на 2.
такswrСначала данные будут извлекаться параллельно, а зависимые выборки будут повторяться до тех пор, пока восходящий поток не будет готов. Этот простой режим несколько снижает производительность (не повторяя нисходящий поток вовремя после того, как восходящий поток готов), но это разумное решение, и максимизация параллелизма также делает большинство сцен более производительными, чем рукописные.
4 Резюме
Автор оставляет два вопроса для студентов, внимательно прочитавших эту статью:
- Что вы думаете о хуках или потоке данных?
- Есть ли лучший способ улучшить решение swr для зависимой выборки?
Адрес обсуждения:Интенсивное чтение "Извлечение хуков - исходный код swr" · Issue #216 · dt-fe/weekly
Если вы хотите принять участие в обсуждении, пожалуйста,кликните сюда, с новыми темами каждую неделю, выходящими по выходным или понедельникам. Интерфейс интенсивного чтения — поможет вам отфильтровать надежный контент.
Сфокусируйся наАккаунт WeChat для интенсивного чтения в интерфейсе
Заявление об авторских правах: Бесплатная перепечатка - некоммерческая - не производная - сохранить авторство (Лицензия Creative Commons 3.0)