Начало работы
Установка
Внутри директории вашего React-проекта, выполните команду:
pnpm add swr
Быстрый старт
Для обычных RESTful API с данными JSON сначала необходимо создать функцию fetcher
, которая является
просто оболочкой для нативного fetch
:
const fetcher = (...args) => fetch(...args).then(res => res.json())
Если вы хотите использовать GraphQL API или библиотеки, такие как Axios, вы можете создать свою собственную fetcher-функцию. Смотрите примеры здесь.
Затем можете импортировать useSWR
и использовать его внутри функциональных компонентов:
import useSWR from 'swr'
function Profile () {
const { data, error, isLoading } = useSWR('/api/user/123', fetcher)
if (error) return <div>ошибка загрузки</div>
if (isLoading) return <div>загрузка...</div>
// рендер данных
return <div>привет, {data.name}!</div>
}
Обычно существует 3 возможных состояния запроса: «загрузка», «готово» или «ошибка». Вы можете использовать
значение data
, error
и isLoading
, чтобы определить текущее состояние запроса и вернуть соответствующий UI.
Делайте многоразовыми
При создании веб-приложения вам может потребоваться повторно использовать данные во многих местах пользовательского интерфейса. Создавать многоразовые хуки данных поверх SWR невероятно просто:
function useUser (id) {
const { data, error, isLoading } = useSWR(`/api/user/${id}`, fetcher)
return {
user: data,
isLoading,
isError: error
}
}
И используйте их в своих компонентах:
function Avatar ({ id }) {
const { user, isLoading, isError } = useUser(id)
if (isLoading) return <Spinner />
if (isError) return <Error />
return <img src={user.avatar} />
}
Используя этот шаблон, вы можете забыть об императивном получении данных: отправить запрос, обновить состояние загрузки и вернуть окончательный результат. Вместо этого ваш код более декларативен: вам просто нужно указать, какие данные используются компонентом.
Пример
В реальном примере наш веб-сайт показывает панель навигации и контент, оба зависят от user
:
Традиционно мы получаем данные один раз, используя useEffect
в компоненте верхнего уровня,
и передаем их дочерним компонентам через пропсы (обратите внимание, что мы пока не обрабатываем
состояние ошибки):
// компонент страницы
function Page () {
const [user, setUser] = useState(null)
// выборка данных
useEffect(() => {
fetch('/api/user')
.then(res => res.json())
.then(data => setUser(data))
}, [])
// глобальное состояние загрузки
if (!user) return <Spinner/>
return <div>
<Navbar user={user} />
<Content user={user} />
</div>
}
// дочерний компонент
function Navbar ({ user }) {
return <div>
...
<Avatar user={user} />
</div>
}
function Content ({ user }) {
return <h1>С возвращением, {user.name}</h1>
}
function Avatar ({ user }) {
return <img src={user.avatar} alt={user.name} />
}
Обычно нам нужно сохранить выборку всех данных в компоненте верхнего уровня и передавать пропсы к каждому компоненту в глубине дерева. Код станет труднее поддерживать, если мы добавим на страницу больше зависимостей данных.
Хотя мы можем избежать передачи пропсов с помощью Контекста (opens in a new tab), всё ещё существует проблема с динамическим контентом: компоненты внутри контента страницы могут быть динамическими, и компонент верхнего уровня может не знать, какие данные потребуются его дочерним компонентам.
SWR отлично решает проблему. С помощью только что созданного хука useUser
код можно реорганизовать так:
// компонент страницы
function Page () {
return <div>
<Navbar />
<Content />
</div>
}
// дочерний компонент
function Navbar () {
return <div>
...
<Avatar />
</div>
}
function Content () {
const { user, isLoading } = useUser()
if (isLoading) return <Spinner />
return <h1>С возвращением, {user.name}</h1>
}
function Avatar () {
const { user, isLoading } = useUser()
if (isLoading) return <Spinner />
return <img src={user.avatar} alt={user.name} />
}
Теперь данные привязаны к компонентам, которым нужны данные, и все компоненты независимы друг от друга. Всем родительским компонентам не нужно ничего знать о данных или об их передаче. Они просто рендерят. Код стал намного проще и легче в обслуживании.
Самым прекрасным является то, что в API будет отправлен всего 1 запрос, потому что они используют один и тот же ключ SWR, а запрос автоматически выводится, кешируется и распределяется.
Кроме того, приложение теперь имеет возможность обновлять данные при фокусе или переподключении к сети! Это означает, что когда ноутбук пользователя выходит из спящего режима или он переключается между вкладками браузера, данные обновляются автоматически.