Написать пост

React 18: новые хуки и как изменился рендеринг

Обзор на обновления React 18 с примерами кода: automatic batching, concurrent rendering и новые хуки.

26К открытий28К показов

В этом материале мы рассмотрим часть обновлений, которые для нас приготовил React 18 — разберем automatic batching, concurrent rendering, изменения в архитектуре приостановки рендеринга на стороне сервера и новые хуки.

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

Automatic batching

React 18 добавляет возможность автоматического батчинга обновления состояний для асинхронных операций. Например, promise, таймауты, fetch-запросы. Это положительно сказывается на производительности.

Батчингом в React называют процесс группировки нескольких вызовов обновления состояний в один этап ререндера. Другими словами, пакетная обработка.

Раньше группировка происходила только внутри обработчиков событий.

			function App() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  function handleClick() { 
    // До React 18 следующие вызовы не батчились
    // Установка состояния происходит «после» события в колбэке асинхронного вызова
    fetchSomething().then(() => {
      setCount(c => c + 1); // Спровоцирует ререндер
      setFlag(f => !f); // Спровоцирует ререндер
    });
    
    // В React 18
    fetchSomething().then(() => {
      setCount(c => c + 1); // Не вызывает ререндер
      setFlag(f => !f); // Не вызывает ререндер
// React будет вызывать ререндер только один раз, в конце
    })
  }
  return (
  <div>
    <button onClick={handleClick}>Next</button>
    <h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1>
  </div>
         );
}
		

Concurrent rendering и новые хуки

Concurrent rendering (конкурентный режим) предназначен для более плавной работы приложения на устройстве пользователя. Одна из областей применения —  прерываемый рендеринг. Представьте, что пользователь вводит в строку поиска текст. Событие обновляет состояние компонента, и происходит рендер нового списка результатов. Во время этого процесса залипает ввод: браузер не может обновить введенный в поле текст, т.к. занимается рендером нового списка результатов. Конкурентный режим исправляет это ограничение и делает рендер прерываемым.

С новыми фичами конкурентного рендеринга были добавлены и новые API: переходы состояния (state transition), фичи задержки (Suspense) и новые хуки.

startTransition

Метод API добавлен для обновления состояния компонента, которое влечет за собой тяжелые вычисления. Например, фильтрация списка. Это позволяет значительно улучшить пользовательский ввод и отклик интерфейса, т.к. помечает тяжелые обновления компонента как «переходы» — transitions.

В API представлено в виде функции startTransition, в которую помещают обновления состояний, являющихся несрочными — non-urgent.

			import { startTransition } from 'react';

// Срочное (urgent) обновление: отображаем введенный текст
setInputValue(input);

// Помечаем обновления состояний как переходы
startTransition(() => {
  // Переход: фильтрация списка по введенному ключевому слову
  setSearchQuery(input);
});
		

startTransition полезен, если вы хотите сделать пользовательский ввод быстрым, не было фриза UI, а несрочные операции выполнялись на фоне.

useTransition

Помимо startTransition появился новый хук useTransition. Он позволяет узнать статус перехода:

			import { useTransition } from 'react';
const [isPending, startTransition] = useTransition();
		

useDeferredValue

Вернет отложенную версию переданного значения, которая будет «отставать» от исходной на время, равное таймауту:

			import { useDeferredValue } from 'react';
// ...
const [text, setText] = useState("text");
const deferredText = useDeferredValue(text, { timeoutMs: 2000 });
		

Когда полезен новый хук: нужно реализовать отзывчивый и быстрый для пользователя интерфейс. Компонент, с которым взаимодействует пользователь, будет быстро перерисовываться на каждый ввод. При этом не будут происходить лишние перерендеры тяжелого компонента.

Улучшения Suspense

Suspense предназначен для отображения запасного интерфейса (спиннера) во время ожидания дочерних компонентов. Дочерние компоненты в это время могут выполнять асинхронные вызовы API, либо загружаться через lazy load.

Основное нововведение заключается в том, что фича стала стабильной. Получила большие архитектурные изменения под капотом и приобрела название «Конкурентные задержки» (Concurrent Suspense). Смена названия никак не отразится на пользователях React. Существенное изменение для пользователей заключается в рендере дочерних элементов внутри Suspense:

			const App = () => {
  return (
    }>
<Suspense fallback={<Loading />}>
<SuspendedComponent />
<Sibling />
</Suspense>
  );
};
		

В React 17 компонент будет смонтирован и вызваны его эффекты. Затем он будет скрыт.

Теперь в React 18 компонент смонтируется только после того, как загрузится.

SuspenseList

Предназначен для определения порядка, в котором загружаются и отображаются пользователю напрямую вложенные компоненты Suspense и SuspenseList.

			<SuspenseList revealOrder="forwards">
<Suspense fallback={'Загрузка...'}>
<ProfilePicture id={1} />
</Suspense>
<Suspense fallback={'Загрузка...'}>
<ProfilePicture id={2} />
</Suspense>
<Suspense fallback={'Загрузка...'}>
<ProfilePicture id={3} />
</Suspense>
</SuspenseList>
		

Бывают случаи, когда на UI необходимо отобразить компоненты в определенном порядке. Если обернуть их в ​​SuspenseList, то React не отобразит компонент, пока не загрузится предыдущий из списка.

Потоковый SSR

Внесены большие улучшения в Suspense Server-Side-Rendering (SSR). Рассмотрим основные фичи:

Выборочная гидратация.

Метод hydrate() используется в SSR и позволяет повесить обработчики событий на узлы DOM-дерева, которые были отрендерены на стороне сервера. Это позволяет улучшить опыт клиента при первой загрузки страницы.

React начнет гидратацию компонентов с учетом взаимодействия пользователя с содержимым сайта. Например, при клике на комментарий React приоритезирует гидратацию HTML родительских блоков.

Еще одна особенность в том, что React не будет блокировать UI во время гидратации — этот процесс будет происходить во время простоя браузера. Поэтому пользовательские события будут обрабатываться сразу.

Потоковая отправка HTML

Позволяет отправить HTML клиенту без загрузки всех данных для рендера на сервер. Как только данные будут получены, они отрендерятся на сервере и отправятся на клиент. Например, есть блок с комментариями, и мы можем асинхронно загружать по ним информацию, отдавая HTML. Когда комментарии будут получены, отрендерить их и отправить клиенту в конце HTML-документа.

Что нужно сделать, чтобы пользоваться новыми функционалом React 18?

Обновление. Установка последней версии

			npm install react react-dom
		

или

			yarn add react react-dom
		

Обновление API рендеринга

React 18 представляет новый корневой API, который обеспечивает лучшую эргономику для управления корнями. Новый API также включает новый параллельный рендеринг, который позволяет вам использовать параллельные функции.

			// Before
import { render } from 'react-dom';
const container = document.getElementById('app');
render(, container);
// After
import { createRoot } from 'react-dom/client';
const container = document.getElementById('app');
const root = createRoot(container); 
root.render();
		

Если ваше приложение использует рендеринг на стороне сервера с гидратацией, обновите hydrate до hydrateRoot:

			// Before
import { hydrate } from 'react-dom';
const container = document.getElementById('app');
hydrate(, container);

// After
import { hydrateRoot } from 'react-dom/client';
const container = document.getElementById('app');
const root = hydrateRoot(container, );
		
Следите за новыми постами
Следите за новыми постами по любимым темам
26К открытий28К показов