SWR - библиотека для запросов

16 июня 2026
Автор

Олег Марков

Введение

Когда вы разрабатываете React-приложение, рано или поздно перед вами встаёт вопрос: как правильно получать данные с сервера? На первый взгляд всё кажется простым — достаточно useEffect и useState. Но по мере роста приложения возникают проблемы: данные устаревают, пользователь видит неактуальную информацию, приходится вручную управлять состояниями загрузки и ошибок, а дублирующиеся запросы снижают производительность.

SWR — это библиотека от команды Vercel, созданная специально для решения этих задач. Название расшифровывается как stale-while-revalidate — HTTP стратегия кэширования, описанная в RFC 5861. Суть стратегии: возвращай кэшированные (устаревшие) данные немедленно, а в фоне отправляй запрос для получения актуальных данных и обновляй UI.

В результате пользователь видит данные мгновенно — без задержки, которая была бы при обычном запросе. А когда приходит свежий ответ, интерфейс тихо обновляется. Это создаёт ощущение быстрого и отзывчивого приложения.

В этой статье вы узнаете, как установить и использовать SWR, разберётесь с хуком useSWR, научитесь создавать кастомные fetcher-функции, настраивать глобальную конфигурацию, делать мутации, реализовывать пагинацию и бесконечную прокрутку, а также сравните SWR с TanStack Query.

Установка

Установка SWR максимально проста — библиотека не имеет обязательных зависимостей:

npm install swr

Или с помощью yarn:

yarn add swr

SWR поставляется с TypeScript-типами из коробки — отдельно устанавливать @types/swr не нужно.

Базовое использование useSWR

Центральный хук библиотеки — useSWR. Его сигнатура выглядит следующим образом:

const { data, error, isLoading, isValidating } = useSWR(key, fetcher, options?)
  • key — уникальный ключ запроса (обычно URL). Если null — запрос не будет выполнен.
  • fetcher — функция, которая принимает key и возвращает промис с данными.
  • options — необязательный объект с настройками.

Возвращаемые значения:

  • data — результат запроса (или undefined пока идёт загрузка).
  • error — ошибка, если запрос завершился неудачно.
  • isLoadingtrue если данных ещё нет и идёт загрузка.
  • isValidatingtrue если идёт ревалидация (данные есть, но запрашиваются новые).

Вот простейший пример получения данных:

import useSWR from 'swr'

// Простая fetcher-функция
const fetcher = (url: string) => fetch(url).then(res => res.json())

interface User {
  id: number
  name: string
  email: string
}

function UserProfile({ userId }: { userId: number }) {
  const { data, error, isLoading } = useSWR<User>(
    `/api/users/${userId}`,
    fetcher
  )

  if (isLoading) return <div>Загрузка...</div>
  if (error) return <div>Ошибка: {error.message}</div>
  if (!data) return null

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.email}</p>
    </div>
  )
}

Обратите внимание: здесь не нужны useState и useEffect — SWR управляет состоянием за вас.

Автоматическая дедупликация

Если несколько компонентов используют один и тот же ключ, SWR автоматически дедуплицирует запросы — отправляется только один HTTP-запрос, а все компоненты получают одни и те же данные:

// Оба компонента используют один ключ — запрос будет только один
function ComponentA() {
  const { data } = useSWR('/api/user', fetcher)
  return <div>{data?.name}</div>
}

function ComponentB() {
  const { data } = useSWR('/api/user', fetcher)
  return <div>{data?.email}</div>
}

Это особенно полезно, когда один и тот же запрос нужен в разных частях дерева компонентов.

Fetcher функция

Fetcher — это любая асинхронная функция, которая принимает ключ SWR и возвращает данные. SWR не привязан к конкретному HTTP-клиенту, и вы можете использовать любой: fetch, axios, ky и другие.

Fetcher с нативным fetch

const fetcher = async (url: string) => {
  const res = await fetch(url)

  // Важно: fetch не бросает ошибку при статусах 4xx/5xx
  if (!res.ok) {
    const error = new Error('Ошибка при запросе данных')
    // Добавляем дополнительную информацию к ошибке
    ;(error as any).status = res.status
    throw error
  }

  return res.json()
}

Fetcher с axios

import axios from 'axios'

const fetcher = (url: string) => axios.get(url).then(res => res.data)

Fetcher с несколькими аргументами

Когда для запроса нужно передать несколько параметров (например, URL и токен авторизации), ключ SWR может быть массивом:

const fetcher = async ([url, token]: [string, string]) => {
  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${token}` }
  })
  return res.json()
}

function Profile() {
  const token = useAuthToken()
  const { data } = useSWR(['/api/profile', token], fetcher)

  return <div>{data?.name}</div>
}

SWR сравнивает ключи по значению, поэтому при изменении любого элемента массива будет автоматически выполнен новый запрос.

Глобальный fetcher

Чтобы не передавать fetcher в каждый вызов useSWR, его можно задать глобально через SWRConfig:

import { SWRConfig } from 'swr'

const globalFetcher = (url: string) => fetch(url).then(res => res.json())

function App() {
  return (
    <SWRConfig value={{ fetcher: globalFetcher }}>
      <MyApp />
    </SWRConfig>
  )
}

// Теперь fetcher можно не передавать явно
function UserProfile() {
  const { data } = useSWR('/api/user') // fetcher берётся из контекста
  return <div>{data?.name}</div>
}

Глобальная конфигурация с SWRConfig

SWRConfig позволяет задать настройки по умолчанию для всех useSWR хуков внутри дерева компонентов. Это удобно для настройки общего поведения без дублирования кода в каждом хуке.

import { SWRConfig } from 'swr'

function App() {
  return (
    <SWRConfig
      value={{
        fetcher: (url: string) => fetch(url).then(res => res.json()),
        revalidateOnFocus: true,        // ревалидировать при фокусе окна
        revalidateOnReconnect: true,     // ревалидировать при восстановлении сети
        refreshInterval: 0,              // автообновление (0 = отключено)
        dedupingInterval: 2000,          // интервал дедупликации (мс)
        errorRetryCount: 3,              // количество повторных попыток при ошибке
        shouldRetryOnError: true,        // повторять при ошибке
        loadingTimeout: 3000,            // таймаут загрузки (мс)
        onError: (error) => {
          console.error('SWR Error:', error)
        },
        onSuccess: (data, key) => {
          console.log('Успешный запрос:', key, data)
        },
      }}
    >
      <MyApp />
    </SWRConfig>
  )
}

Вложенные конфигурации

SWRConfig можно вкладывать — дочерняя конфигурация переопределяет родительскую:

function AdminPanel() {
  return (
    // Для этого раздела увеличиваем частоту обновления
    <SWRConfig value={{ refreshInterval: 5000 }}>
      <AdminDashboard />
    </SWRConfig>
  )
}

Доступ к глобальной конфигурации

Если нужно прочитать текущую конфигурацию внутри компонента, используйте хук useSWRConfig:

import { useSWRConfig } from 'swr'

function MyComponent() {
  const { mutate, cache } = useSWRConfig()

  // mutate — функция для ручного обновления кэша
  // cache — объект кэша
}

Мутации и обновление данных

SWR предоставляет два способа мутаций: bound mutate (привязана к конкретному ключу) и global mutate (глобальная).

Bound mutate

Функция mutate, возвращаемая из useSWR, автоматически привязана к ключу хука:

import useSWR from 'swr'

interface Todo {
  id: number
  title: string
  completed: boolean
}

function TodoItem({ id }: { id: number }) {
  const { data, mutate } = useSWR<Todo>(`/api/todos/${id}`, fetcher)

  const toggleTodo = async () => {
    if (!data) return

    // Оптимистичное обновление: сначала обновляем UI
    await mutate(
      { ...data, completed: !data.completed },
      { revalidate: false } // не ревалидируем сразу
    )

    // Затем отправляем запрос на сервер
    try {
      await fetch(`/api/todos/${id}`, {
        method: 'PATCH',
        body: JSON.stringify({ completed: !data.completed }),
        headers: { 'Content-Type': 'application/json' },
      })
      // Ревалидируем для синхронизации с сервером
      mutate()
    } catch (error) {
      // При ошибке откатываемся
      mutate(data)
    }
  }

  return (
    <div>
      <span style={{ textDecoration: data?.completed ? 'line-through' : 'none' }}>
        {data?.title}
      </span>
      <button onClick={toggleTodo}>Переключить</button>
    </div>
  )
}

Global mutate

Глобальная mutate из useSWRConfig позволяет обновить данные для любого ключа из любого места приложения:

import { useSWRConfig } from 'swr'

function AddTodo() {
  const { mutate } = useSWRConfig()

  const addTodo = async (title: string) => {
    // Отправляем запрос
    await fetch('/api/todos', {
      method: 'POST',
      body: JSON.stringify({ title }),
      headers: { 'Content-Type': 'application/json' },
    })

    // Инвалидируем список todos — SWR перезапросит данные
    mutate('/api/todos')
  }

  return (
    <button onClick={() => addTodo('Новая задача')}>
      Добавить задачу
    </button>
  )
}

Оптимистичные обновления через mutate

Паттерн оптимистичного обновления позволяет немедленно обновить UI, не дожидаясь ответа сервера:

import useSWR, { mutate } from 'swr'

interface User {
  name: string
  email: string
}

function UserSettings() {
  const { data } = useSWR<User>('/api/user', fetcher)

  const updateName = async (newName: string) => {
    // Оптимистично обновляем данные с отложенной ревалидацией
    await mutate(
      '/api/user',
      async (currentUser: User | undefined) => {
        // Отправляем запрос на сервер
        const updatedUser = await fetch('/api/user', {
          method: 'PUT',
          body: JSON.stringify({ name: newName }),
          headers: { 'Content-Type': 'application/json' },
        }).then(res => res.json())

        return updatedUser
      },
      {
        optimisticData: { ...data!, name: newName }, // немедленно обновляем UI
        rollbackOnError: true,                        // откат при ошибке
        populateCache: true,                          // обновляем кэш
        revalidate: false,                            // не ревалидируем после
      }
    )
  }

  return (
    <div>
      <p>Имя: {data?.name}</p>
      <button onClick={() => updateName('Новое имя')}>
        Обновить имя
      </button>
    </div>
  )
}

Условные запросы (Conditional Fetching)

Иногда запрос нужно выполнять только при определённых условиях. В SWR для этого достаточно передать null (или функцию, возвращающую null) в качестве ключа — запрос не будет выполнен:

function UserProfile({ userId }: { userId: string | null }) {
  // Запрос выполняется только если userId не null
  const { data } = useSWR(
    userId ? `/api/users/${userId}` : null,
    fetcher
  )

  if (!userId) return <div>Войдите в систему</div>
  if (!data) return <div>Загрузка...</div>

  return <div>{data.name}</div>
}

Зависимые запросы

Часто второй запрос зависит от результата первого. SWR позволяет легко реализовать такой паттерн:

function UserPosts() {
  // Сначала получаем пользователя
  const { data: user } = useSWR('/api/user', fetcher)

  // Запрос к постам выполнится только после получения user.id
  const { data: posts } = useSWR(
    user ? `/api/posts?userId=${user.id}` : null,
    fetcher
  )

  if (!user) return <div>Загрузка пользователя...</div>
  if (!posts) return <div>Загрузка постов...</div>

  return (
    <ul>
      {posts.map((post: any) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

Условный запрос с функцией

Ключ может быть функцией — если она бросает исключение или возвращает falsy значение, запрос не выполняется:

function ConditionalFetch() {
  const [shouldFetch, setShouldFetch] = useState(false)

  const { data } = useSWR(
    () => shouldFetch ? '/api/data' : null,
    fetcher
  )

  return (
    <div>
      <button onClick={() => setShouldFetch(true)}>Загрузить</button>
      {data && <pre>{JSON.stringify(data, null, 2)}</pre>}
    </div>
  )
}

Pagination и Infinite Loading с useSWRInfinite

Для пагинации и бесконечной прокрутки SWR предоставляет специальный хук useSWRInfinite.

Базовая пагинация

import useSWRInfinite from 'swr/infinite'

interface Post {
  id: number
  title: string
  body: string
}

interface PostsPage {
  posts: Post[]
  hasMore: boolean
}

const PAGE_SIZE = 10

function PostList() {
  const { data, error, isLoading, size, setSize } = useSWRInfinite<PostsPage>(
    // Функция-ключ: принимает индекс страницы и данные предыдущей страницы
    (pageIndex, previousPageData) => {
      // Если предыдущая страница пустая или нет следующей — останавливаемся
      if (previousPageData && !previousPageData.hasMore) return null

      return `/api/posts?page=${pageIndex + 1}&limit=${PAGE_SIZE}`
    },
    fetcher
  )

  const posts = data ? data.flatMap(page => page.posts) : []
  const isLoadingMore = isLoading || (size > 0 && data && typeof data[size - 1] === 'undefined')
  const hasMore = data ? data[data.length - 1]?.hasMore : false

  if (error) return <div>Ошибка загрузки</div>

  return (
    <div>
      <ul>
        {posts.map(post => (
          <li key={post.id}>
            <h3>{post.title}</h3>
            <p>{post.body}</p>
          </li>
        ))}
      </ul>

      {hasMore && (
        <button
          onClick={() => setSize(size + 1)}
          disabled={isLoadingMore}
        >
          {isLoadingMore ? 'Загрузка...' : 'Загрузить ещё'}
        </button>
      )}
    </div>
  )
}

Бесконечная прокрутка с Intersection Observer

Для автоматической загрузки при прокрутке используйте IntersectionObserver:

import { useRef, useEffect } from 'react'
import useSWRInfinite from 'swr/infinite'

function InfinitePostList() {
  const loadMoreRef = useRef<HTMLDivElement>(null)

  const { data, size, setSize, isValidating } = useSWRInfinite(
    (index) => `/api/posts?page=${index + 1}&limit=10`,
    fetcher
  )

  // Автоматически подгружаем при появлении элемента в viewport
  useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0].isIntersecting && !isValidating) {
          setSize(size + 1)
        }
      },
      { threshold: 0.1 }
    )

    if (loadMoreRef.current) {
      observer.observe(loadMoreRef.current)
    }

    return () => observer.disconnect()
  }, [size, setSize, isValidating])

  const posts = data ? data.flatMap((page: any) => page.posts) : []

  return (
    <div>
      {posts.map((post: any) => (
        <div key={post.id}>
          <h3>{post.title}</h3>
        </div>
      ))}

      {/* Элемент-триггер для подгрузки */}
      <div ref={loadMoreRef} style={{ height: 20 }}>
        {isValidating && <span>Загрузка...</span>}
      </div>
    </div>
  )
}

Курсорная пагинация

SWR хорошо подходит для API с курсорной пагинацией:

interface PostsCursorResponse {
  items: Post[]
  nextCursor: string | null
}

function CursorPaginatedList() {
  const { data, size, setSize } = useSWRInfinite<PostsCursorResponse>(
    (pageIndex, previousPageData) => {
      if (previousPageData && !previousPageData.nextCursor) return null
      if (pageIndex === 0) return '/api/posts?limit=10'
      return `/api/posts?limit=10&cursor=${previousPageData?.nextCursor}`
    },
    fetcher
  )

  const allItems = data ? data.flatMap(page => page.items) : []
  const hasMore = data ? !!data[data.length - 1]?.nextCursor : false

  return (
    <div>
      {allItems.map(item => (
        <div key={item.id}>{item.title}</div>
      ))}
      {hasMore && (
        <button onClick={() => setSize(size + 1)}>Загрузить ещё</button>
      )}
    </div>
  )
}

Revalidation: при фокусе и при переподключении

SWR автоматически ревалидирует данные в двух ключевых сценариях. Это одна из наиболее ценных возможностей библиотеки.

Ревалидация при фокусе окна

Когда пользователь переключается в другое приложение, а потом возвращается на вкладку браузера, SWR автоматически обновляет данные. Это гарантирует, что пользователь всегда видит актуальную информацию.

function StockPrice() {
  const { data } = useSWR('/api/stock/AAPL', fetcher, {
    revalidateOnFocus: true,   // включено по умолчанию
    focusThrottleInterval: 5000 // не чаще раза в 5 секунд
  })

  return <div>Цена: ${data?.price}</div>
}

Для отключения:

const { data } = useSWR('/api/data', fetcher, {
  revalidateOnFocus: false
})

Ревалидация при переподключении к сети

Если пользователь теряет интернет, а потом восстанавливает соединение, SWR автоматически перезапрашивает данные. Это особенно важно для мобильных приложений.

function LiveData() {
  const { data } = useSWR('/api/live-data', fetcher, {
    revalidateOnReconnect: true // включено по умолчанию
  })

  return <div>{data?.value}</div>
}

Автоматическое обновление по интервалу

Для данных, которые нужно обновлять регулярно (например, биржевые котировки или статусы задач):

function OrderStatus({ orderId }: { orderId: string }) {
  const { data } = useSWR(
    `/api/orders/${orderId}/status`,
    fetcher,
    {
      // Обновляем каждые 3 секунды
      refreshInterval: 3000,
      // Только пока вкладка активна
      refreshWhenHidden: false,
      // Только при наличии сети
      refreshWhenOffline: false,
    }
  )

  return <div>Статус заказа: {data?.status}</div>
}

Ручная ревалидация

Помимо автоматической, можно вызвать ревалидацию вручную:

function DataWithRefresh() {
  const { data, mutate } = useSWR('/api/data', fetcher)

  return (
    <div>
      <pre>{JSON.stringify(data, null, 2)}</pre>
      <button onClick={() => mutate()}>Обновить данные</button>
    </div>
  )
}

Первоначальная загрузка без ревалидации

Если данные уже доступны (например, от SSR), можно передать их как начальные и отключить немедленную ревалидацию:

function Page({ serverData }: { serverData: any }) {
  const { data } = useSWR('/api/data', fetcher, {
    fallbackData: serverData,
    revalidateIfStale: false,  // не ревалидировать при наличии кэшированных данных
    revalidateOnMount: false,  // не ревалидировать при монтировании
  })

  return <div>{data?.title}</div>
}

Обработка ошибок

SWR автоматически повторяет запросы при ошибках с экспоненциальной задержкой:

function DataWithErrors() {
  const { data, error } = useSWR('/api/data', fetcher, {
    onErrorRetry: (error, key, config, revalidate, { retryCount }) => {
      // Не повторяем для 404 ошибок
      if (error.status === 404) return

      // Максимум 3 попытки
      if (retryCount >= 3) return

      // Повторяем через 5 секунд
      setTimeout(() => revalidate({ retryCount }), 5000)
    }
  })

  if (error) {
    if (error.status === 404) return <div>Данные не найдены</div>
    return <div>Произошла ошибка. Повторяем...</div>
  }

  return <div>{data?.name}</div>
}

Глобальная обработка ошибок

<SWRConfig
  value={{
    onError: (error, key) => {
      if (error.status !== 403 && error.status !== 404) {
        // Отправляем ошибку в систему мониторинга
        reportError(error, { key })
      }
    }
  }}
>
  <App />
</SWRConfig>

Предзагрузка данных (Preloading)

SWR поддерживает предзагрузку данных до того, как компонент смонтируется:

import { preload } from 'swr'

// Предзагружаем данные сразу при загрузке модуля
preload('/api/user', fetcher)

function App() {
  return <UserProfile />
}

function UserProfile() {
  // Данные уже в кэше — нет задержки
  const { data } = useSWR('/api/user', fetcher)
  return <div>{data?.name}</div>
}

Интеграция с Next.js (SSR/SSG)

SWR хорошо интегрируется с Next.js, позволяя использовать серверные данные как начальные:

// pages/profile.tsx
import { GetServerSideProps } from 'next'
import useSWR, { SWRConfig } from 'swr'

function Profile() {
  // На сервере данные уже в fallback — загрузка мгновенная
  const { data } = useSWR('/api/user', fetcher)
  return <div>{data?.name}</div>
}

export default function Page({ fallback }: { fallback: any }) {
  return (
    <SWRConfig value={{ fallback }}>
      <Profile />
    </SWRConfig>
  )
}

export const getServerSideProps: GetServerSideProps = async () => {
  const user = await fetchUser()
  return {
    props: {
      fallback: {
        '/api/user': user
      }
    }
  }
}

SWR vs React Query — сравнение

Оба инструмента решают схожие задачи, но имеют разные приоритеты. Вот подробное сравнение:

Размер и зависимости

  • SWR: ~4 KB gzipped, без зависимостей
  • React Query: ~13 KB gzipped, без зависимостей

SWR выигрывает по размеру — это важно для проектов, где критична скорость загрузки.

API и концепции

// SWR — минималистичный API
const { data, error, isLoading, mutate } = useSWR('/api/user', fetcher)

// TanStack Query — более явный API с большим количеством опций
const { data, error, isLoading, refetch } = useQuery({
  queryKey: ['user'],
  queryFn: fetchUser,
})

TanStack Query требует явного указания queryKey и queryFn. SWR использует URL как ключ и fetcher-функцию — API проще.

Мутации

// SWR — мутации через mutate
const { mutate } = useSWR('/api/user', fetcher)
await mutate(newData, { revalidate: false })

// TanStack Query — специальный хук useMutation
const mutation = useMutation({
  mutationFn: updateUser,
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ['user'] })
  }
})
mutation.mutate(newData)

TanStack Query предоставляет более богатый API для мутаций: onMutate, onSuccess, onError, onSettled.

DevTools

  • SWR: нет официальных DevTools
  • TanStack Query: мощные DevTools из коробки (@tanstack/react-query-devtools)

Для отладки сложных приложений TanStack Query имеет явное преимущество.

Кэширование и инвалидация

// TanStack Query — явная инвалидация по тегам
queryClient.invalidateQueries({ queryKey: ['posts'] })
// Инвалидирует все запросы с ключом, начинающимся на 'posts'

// SWR — ревалидация конкретного ключа или по регулярному выражению
mutate('/api/posts')
mutate(key => typeof key === 'string' && key.startsWith('/api/posts'))

TanStack Query предоставляет более гибкую систему инвалидации через иерархические ключи.

Пагинация

// SWR useSWRInfinite
const { data, size, setSize } = useSWRInfinite(
  (index) => `/api/posts?page=${index}`,
  fetcher
)

// TanStack Query useInfiniteQuery
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
  queryKey: ['posts'],
  queryFn: ({ pageParam = 0 }) => fetchPosts(pageParam),
  getNextPageParam: (lastPage) => lastPage.nextCursor,
})

TanStack Query имеет более удобный API для курсорной пагинации через getNextPageParam.

Когда выбрать SWR

  • Небольшие и средние проекты
  • Когда важен минимальный размер бандла
  • Когда нужна простота API
  • Проекты на Next.js (SWR от той же команды — Vercel)
  • Когда большинство операций — это GET-запросы

Когда выбрать TanStack Query

  • Крупные проекты с множеством мутаций
  • Когда нужны DevTools для отладки
  • Когда важна гибкая система инвалидации кэша
  • Проекты с оффлайн-поддержкой
  • Когда нужен React Native (TanStack Query поддерживает обе платформы)

Итоговая таблица

Характеристика SWR TanStack Query
Размер ~4 KB ~13 KB
API сложность Простой Средний
Мутации Базовые Расширенные
DevTools Нет Есть
Infinite loading Есть Есть
Оффлайн поддержка Базовая Расширенная
TypeScript Отличный Отличный
React Native Нет Да

Итог

SWR — это мощная, лаконичная библиотека, которая реализует стратегию stale-while-revalidate для управления серверными данными в React. Её ключевые преимущества:

  • Простота: минималистичный API, быстрое освоение
  • Производительность: дедупликация запросов, автоматическое кэширование
  • Надёжность: автоматическая ревалидация при фокусе и reconnect
  • Гибкость: поддержка любого HTTP-клиента через fetcher

Если вы ищете лёгкую библиотеку для работы с серверными данными и ваш проект не требует сложной системы мутаций или DevTools — SWR отличный выбор. Для проектов с высокими требованиями к управлению серверным состоянием присмотритесь к TanStack Query.

В обоих случаях вы уйдёте от ручного управления useEffect и useState к декларативному подходу, где библиотека берёт на себя сложности синхронизации данных с сервером.

Стрелочка влевоTailwind CSS с ReactStyled Components — стилизация через JSСтрелочка вправо

Постройте личный план изучения React до уровня Middle — бесплатно!

React — часть карты развития Frontend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по React

Uncontrolled Components: когда DOM управляет даннымиБезопасность в React: защита от XSS, CSRF и утечек данныхRender Props: гибкое управление рендерингом в ReactРефакторинг React-кода: техники и лучшие практикиПрофилирование React: как найти и устранить узкие местаЧастичное применение: как создавать компоненты без лишнего кодаИменование компонентов в React: соглашения и лучшие практикиЛенивая загрузка: как ускорить React-приложение в разыHOC в React: мастерство композиции компонентовuseMemo: как спасти производительность от тяжелых вычисленийError Boundaries: создаем надежные React-приложенияКонтролируемые компоненты в React: полный контроль над формамиCompound Components в React: создаем гибкие компоненты с мощным APIДокументирование компонентов в React: Storybook, JSDoc и READMEКомпозиция компонентов в React: строим гибкие интерфейсыКомментирование кода в React: когда и как писать комментарииCode Splitting в React: как уменьшить бандл и ускорить загрузку приложенияАсинхронные компоненты в React: новый стандарт работы с даннымиДоступность (a11y) в React: ARIA, семантика и клавиатурная навигация
Zustand — управление состоянием в ReactZod - валидация с TypeScriptYup - валидация схемXState - конечные автоматыТемизация в ReactТестирование хуковTailwind CSS с ReactSWR - библиотека для запросовStyled Components — стилизация через JSStorybook - документация компонентовSnapshots тестированиеRTK Query - работа с APIRedux Toolkit - современный ReduxRecoil — библиотека управления состоянием от FacebookВиртуализация списков с react-window: как отображать тысячи элементов без лаговReact Toastify - уведомления в ReactReact Testing LibraryСоздание таблиц в React гайд по react-tableReact Spring - анимацииРабота с формами и селектами в ReactReact Query (TanStack Query) - работа с серверомПлагины в React что это и как их использоватьReact PDF - работа с PDF файламиОбзор популярных библиотек для ReactReact Icons - библиотека иконок для ReactReact Hook Form — валидация форм в ReactReact Dropzone — загрузка файловПодключение Bootstrap к React-приложениюReact Beautiful DnD - перетаскивание элементовАнимация при монтировании компонентов в ReactМокирование APIMobX — реактивное управление состоянием в ReactМикрофронтенды с React (micro-frontends)Загрузка и индикаторыАнимация списков в ReactJotai - атомарное состояниеБесконечная прокруткаFramer Motion - библиотека анимацийEmotion — библиотека CSS-in-JSДинамические стили в ReactE2E тестирование с CypressCSSTransition - переходыCSS-in-JS — плюсы и минусыКонтекст vs Redux — когда что использоватьИспользование Chart.js в ReactAxios с ReactТестирование асинхронных компонентовОбработка ошибок API
useState в React что это и как использоватьuseTransition - плавные переходы между состояниямиuseSyncExternalStore — работа с внешними сторамиuseRef в React — создание ссылок на DOM и значенияuseOptimistic — оптимистичные обновления UIuseLayoutEffect в React — эффект до отрисовкиuseInsertionEffect — внедрение стилей до мутаций DOMuseImperativeHandle в React — настройка ref дочернего компонентаuseId — генерация уникальных идентификаторовuseFormStatus - отслеживание статуса отправки формыuseDeferredValue — отложенное обновление состоянияuseDebugValue — отладка кастомных хуковuseCallback в React — мемоизация функцийuseMemo в React: как и когда оптимизировать тяжелые вычисленияuseEffect в React что это и как использоватьuseContext — работа с контекстом в ReactuseReducer — альтернатива useState для сложной логикиuseCallback в React — мемоизация функций и оптимизация ре-рендеровuseActionState в React 19Оптимизация рендеринга в React: от теории к глубокой практикеЧто такое useRef и как его применять в ReactКак и зачем использовать React HooksУправление состоянием в React через ContextКак предотвратить лишние ре-рендеры в React: полное руководствоuseMemo vs useCallback: подробное руководство по мемоизации в ReactПравила хуков — правила использованияuseEffect vs useLayoutEffect: в чём разница и какой хук выбрать?Кастомные хуки в React — создание собственных хуковuseState продвинутое использование в React
Transition API — плавные обновления интерфейса в ReactReact Suspense — приостановка рендераStrictMode в React — как находить ошибки на этапе разработкиСерверные компоненты React (RSC) — подробный разбор и практикаКак работает рендеринг в ReactЧто такое props в React и как их правильно использоватьКак работает JSX связка React и HTMLЧто такое React.js и как его использоватьКак использовать элементы в ReactКак использовать React DOM в проектеЧто такое компоненты в React и как их применятьРабота с children в ReactПорталы в React: рендер компонентов вне иерархии DOMFragment в React: группировка элементов без лишних узлов DOMCSS Modules в ReactConcurrent Mode — конкурентный режим в React
Открыть базу знаний

Лучшие курсы по теме

изображение курса

React и Redux Toolkit

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий