Что нового в React v18.0?

В React v18.0 появилось несколько интересных новых улучшений.

Когда год назад был анонсирован React 18, команда пообещала стратегию постепенного внедрения. Теперь, год спустя, это именно то, что они сделали, и вы можете обновить свое приложение до последней версии.

Для обновления с React 17 до 18 достаточно простого шага:

1) Установите последнюю версию:

npm install react@18 react-dom@18

Давайте углубимся в новые функции и обновления React 18.0.

1. Устаревший корневой API и новый корневой API

React 18 поставляет два корневых API, которые мы называем Legacy Root API и New Root API.

  • Устаревший корневой API. Это существующий API, вызываемый с помощью ReactDOM.render. Это создает корень, работающий в «устаревшем» режиме, который работает точно так же, как React 17. Перед выпуском команда React добавит в этот API предупреждение о том, что он устарел, и переключится на New Root API.
  • Новый корневой API. Новый корневой API вызывается с помощью ReactDOM.createRoot. Это создает корень, работающий в React 18, который добавляет все улучшения React 18 и позволяет вам использовать параллельные функции. Это будет корневой API в будущем.

Использование:

//React 17
import * as ReactDOM from "react-dom"
import App from "App"

// The <App/> component is directly attached to a DOM element with the id of 'app':
ReactDOM.render(<App />, document.getElementById("app"))

New Root API использует ReactDOM.createRoot(), создает новый корневой элемент, и в нем рендерится приложение React:

//React 18
import * as ReactDOM from "react-dom"
import App from "App"
// Create a root by using ReactDOM.createRoot():
const root = ReactDOM.createRoot(document.getElementById("app"))
// Render the main <App/> element to the root:
root.render(<App/>)

Hydrating в Legacy Root API и Hydrating в новом Root API

import ReactDOM from 'react-dom'
import App from 'App'

//React 17
const container = document.getElementById('app');
ReactDOM.hydrate(<App />, container)
//React 18
const container = document.getElementById('root');
const root = ReactDOM.createRoot(container, { hydrate: true });
root.render(<App />);

2. Параллельные функции

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

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

Параллелизм — это фундаментальное обновление механизма рендеринга React. Параллелизм позволяет React прерывать рендеринг.

React 18 представляет собой основу параллельного рендеринга, а новые функции, такие как приостановка, рендеринг потокового сервера и переходы, основаны на параллельном рендеринге.

React 18 станет первым выпуском React, в котором будет добавлена ​​поддержка параллельных функций, таких как:

  • startTransition: позволяет поддерживать отзывчивость пользовательского интерфейса во время дорогостоящего перехода состояния.

В новом обновлении каждое обновление состояния относится к одной из следующих двух категорий: это либо срочное обновление, либо переходное обновление (для краткости — переход). Срочные обновления — это действия, на которые пользователь интуитивно рассчитывает мгновенно, например, на щелчок мыши или нажатие клавиши. Обновления перехода — это действия, которые допустимы с небольшой задержкой и во многих случаях ожидаются, например, поисковый запрос. startTransitionAPI помечает вызовы setState внутри него как переходы , что означает, что они прерываемы. Обновления перехода также запускаются синхронно, но пользовательский интерфейс не блокируется во время их выполнения.

import { startTransition } from "react"
// Urgent update that shows whatever is typed by the user:
setInputValue(inputData);
// Transition updates are marked with startTransition:
startTransition(() => {
  // A non-urgent, interruptable update of the search query:
  setSearchQuery(inputData);
})

Если бы setSearchQuery(input) не было помечено как обновление перехода, пользовательский интерфейс блокировался бы после каждого изменения ввода. Теперь, когда он помечен как несрочный, пользователь может искать что-либо, менять мнение и решать перейти на другую страницу до того, как пользовательский интерфейс будет обновлен в соответствии с изменением ввода, и ему не нужно ждать обновления пользовательского интерфейса, которое не представляет интереса.

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

import { useTransition } from "react"
const [isPending, startTransition] = useTransition()
// For example, you can show a loading spinner when it's pending:
{
  isPending ? <LoadingSpinner /> : null
}
  • useDeferredValuehook помогает вам отложить обновление некоторой части пользовательского интерфейса на указанный период времени, сохраняя при этом отзывчивость страницы. Вы также можете дать ему необязательный тайм-аут. React попытается обновить отложенное значение, как только сможет. Если он не сделает этого в течение заданного периода времени ожидания, он принудительно запустит обновление, блокируя пользовательский интерфейс в процессе. Другими словами, отложенное значение обновляется с помощью обновления перехода, а не срочного обновления, благодаря чему ваш пользовательский интерфейс остается отзывчивым в процессе.
import { useDeferredValue } from "react"
const deferredValue = useDeferredValue(value, {
  timeoutMs: 3000,
})
  • useId: мы можем использовать этот новый хук для создания нового идентификатора на сервере и в клиенте.
function Checkbox() {
  const id = useId();
  return (
    <>
      <label htmlFor={id}>Do you follow This Dot on Twitter?</label>
      <input id={id} type="checkbox" name="react"/>
    </>
  );
};

3. Автоматическое дозирование

React повторно отображает пользовательский интерфейс только один раз. Это означает, что React пакетирует (или группирует) все изменения вместе, поэтому вместо выполнения одного обновления состояния и повторного рендеринга пользовательского интерфейса, выполнения следующего обновления состояния и повторного рендеринга пользовательского интерфейса выполняется и то, и другое. состояния обновляет и повторно отображает пользовательский интерфейс только один раз.

Пакетная обработка — отличный механизм, который защищает нас от ненужного повторного рендеринга пользовательского интерфейса, но React 17 сделал это только в обработчиках событий. Использование цепочек обещаний, асинхронного кода или обработчиков событий нарушало это поведение. В React 18 пакетная обработка выполняется автоматически в собственных обработчиках событий, промисах и асинхронном коде.

function handleClickEvent() {
  // React 17: Re-rendering happens after both of the states are updated
  // This is also done in React 18 by default.
  setIsLoggedIn(loggedIn => !loggedIn);
  setCount(count => count+ 1);
}
// For the following code blocks, React 18 does automatic batching, but React 17 doesn't.
// 1. Promises:
function handleClickEvent() {
  fetchData().then(() => {
    setIsLoggedIn(loggedIn => !loggedIn)
    setCount(count => count+ 1)
  })
}
// 2. Asynchronous code:
setInterval(() => {
  setIsLoggedIn(loggedIn => !loggedIn)
  setCount(count => count+ 1)
}, 3000)
// 3. Native event handlers:
element.addEventListener("click", () => {
  setIsLoggedIn(loggedIn => !loggedIn)
  setCount(count => count+ 1)
})

4. Новый Suspense SSR и селективная гидратация

  • Рендеринг на стороне сервера, также известный как SSR, — это способ рендеринга веб-страниц, который позволяет создавать HTML-код из компонентов React непосредственно на сервере и делиться HTML-кодом с пользователями. Пользователи могут просмотреть предварительный просмотр страницы через SSR еще до того, как пакет JavaScript загрузится и запустится. Но иногда для обработки JavaScript на серверной части требуется много времени, и это время известно как время гидратации (процесс рендеринга компонентов React и добавления обработчиков событий в HTML-документ, отображаемый на стороне сервера, называется увлажнение).
  • React 18 будет включать архитектурные улучшения производительности React SSR. Новое обновление позволит выполнять потоковую передачу HTML непосредственно на сервере, т. е. сервер отправляет части компонентов по мере их рендеринга с помощью другого компонента, известного как Suspense, который решает, какие части приложения могут загружаться дольше, а какие должны отображаться напрямую. Используя метод выборочной гидратации, компоненты, обернутые Suspense, больше не будут блокировать гидратацию. Каждый готовый компонент начнет заполняться, как только браузер получит его содержимое и код JavaScript.

‹Список приостановок› ‹/Список приостановок›

‹SuspenseList› позволяет вам координировать порядок появления содержимого узлов Suspense поддерева, которое он обертывает, даже если данные поступают в другом порядке. Обычно, если у вас есть несколько родственных границ саспенса, они разрешаются всякий раз, когда это возможно. Однако вы можете захотеть загружать компоненты в определенном порядке, независимо от того, в каком порядке они разрешаются.

import { Suspense, SuspenseList } from "react";
<SuspenseList revealOrder="forwards">
  <Suspense fallback="Loading first item...">
    <FirstItem />
  </Suspense>
  <Suspense fallback="Loading second item...">
    <SecondItem />
  </Suspense>
  <Suspense fallback="Loading third item...">
    <ThirdItem />
  </Suspense>
</SuspenseList>

В приведенном выше примере, даже если третий элемент загружается первым, он будет отображать Loading third item..., пока не будет загружен первый элемент. Когда загружается первый элемент, отображается первый элемент вместе с запасным вариантом для второго и третьего. Только когда второй элемент загружен, все три могут быть отображены.

revealOrderprop может принимать значения forwards, backwards и together. forwardsи backwardsprops позволяют внутренним границам приостановки разрешаться в прямом и обратном порядке. together, с другой стороны, ждет разрешения всех границ, прежде чем визуализировать их все.

Вы также можете указать SuspenseList tailprop. tailprop может принимать значения collapsedи hidden. По умолчанию SuspenseList отображает все запасные варианты. Однако, если вы не хотите отображать резервные копии, вы можете использовать tail="hidden"prop, а если вы хотите отображать не более одного резервного варианта, вы можете использовать tail="collapsed". Таким образом, вы можете создать множество запасных вариантов, не беспокоясь о загромождении области загрузки.

5. Строгий режим

Строгий режим в React 18 имитирует монтирование, размонтирование и повторное монтирование компонента с предыдущим состоянием. Это закладывает основу для многократного использования состояния в будущем, когда React может немедленно монтировать предыдущий экран, повторно монтируя деревья, используя то же состояние компонента перед размонтированием.

Строгий режим гарантирует устойчивость компонентов к многократному монтированию и размонтированию эффектов.

6. Теперь компоненты могут отображать undefined

React больше не выдает ошибку, если вы возвращаете undefined из компонента. Разрешенный компонент возвращает значения, соответствующие допустимым значениям в середине дерева компонентов. Команда React предлагает использовать линтер, чтобы предотвратить такие ошибки, как забывание оператора return перед JSX.

7. Нет предупреждения setState о несмонтированных компонентах

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

Заключение

Как мы видим, React 18 представил готовые улучшения и новые функции, которые выглядят невероятно. Это открыло путь для новых возможностей в разработке приложений React.js.

Ресурсы: