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

Параллельный режим:

React 18 представляет Concurrent Mode как новую функцию, которая расширяет способность React обрабатывать несколько обновлений одновременно. Это приводит к более быстрому и беспрепятственному взаимодействию с пользователем. Параллельный режим отдает приоритет наиболее важным обновлениям и обрабатывает их быстрее.

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

Чтобы использовать параллельный режим в вашем приложении React, вам необходимо поместить свой компонент в компонент React.ConcurrentMode. Ниже приведен пример, иллюстрирующий использование параллельного режима:

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <>
      <h1>Count: {count}</h1>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </>
  );
}

function App() {
  return (
    <React.ConcurrentMode>
      <Counter />
    </React.ConcurrentMode>
  );
}

export default App;

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

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

Следует отметить, что параллельный режим не работает со всеми компонентами React из коробки. Если вы хотите использовать параллельный режим со своими компонентами, вам нужно убедиться, что они «готовы к параллельному режиму». Чтобы сделать компонент готовым к параллельному режиму, вам нужно использовать хук React.useTransition, чтобы указать, какая часть компонента может быть отрисована асинхронно.

Вот пример того, как использовать хук React.useTransition, чтобы сделать компонент готовым к параллельному режиму:

import React, { useState, useTransition } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  const [startTransition, isPending] = useTransition();

  const handleClick = () => {
    startTransition(() => {
      setCount(count + 1);
    });
  };

  return (
    <>
      <h1>Count: {count}</h1>
      <button disabled={isPending} onClick={handleClick}>
        Increment
      </button>
    </>
  );
}

function App() {
  return (
    <React.ConcurrentMode>
      <Counter />
    </React.ConcurrentMode>
  );
}

export default App;

В приведенном выше коде у нас есть модифицированная версия компонента Counter, готовая к параллельному режиму. Мы используем хук React.useTransition, чтобы указать, что функция setCount может выполняться асинхронно. Это позволяет параллельному режиму разделить работу по рендерингу и отдать приоритет наиболее важным обновлениям.

Приостановка:

Приостановка — еще одна новая функция, представленная в React 18, которая упрощает процесс обработки асинхронных операций, таких как получение данных из API. С помощью Suspense вы можете легко управлять состоянием загрузки компонента, пока он ожидает получения данных.

Чтобы использовать приостановку в вашем приложении React, вам нужно обернуть свой компонент внутри компонента React.Suspense и указать резервный компонент для отображения во время выборки данных. Вот пример того, как использовать Suspense:

import React, { useState, Suspense } from 'react';

const fetchUser = async (id) => {
  const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
  const user = await response.json();
  return user;
};

const User = ({ userId }) => {
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetchUser(userId).then((data) => setUser(data));
  }, [userId]);

  if (!user) {
    return <div>Loading...</div>;
  }

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

const App = () => {
  return (
    <div>
      <h1>My App</h1>
      <Suspense fallback={<div>Loading...</div>}>
        <User userId={1} />
      </Suspense>
    </div>
  );
};

export default App;

В приведенном выше коде у нас есть простой пример компонента React, который извлекает пользовательские данные из API и отображает их. Компонент User заключен внутри компонента React.Suspense, а резервный компонент указан для отображения во время выборки данных.

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

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

Вот пример того, как использовать Suspense для обработки нескольких компонентов:

import React, { Suspense } from 'react';

const Component1 = React.lazy(() => import('./Component1'));
const Component2 = React.lazy(() => import('./Component2'));
const Component3 = React.lazy(() => import('./Component3'));

const App = () => {
  return (
    <div>
      <h1>My App</h1>
      <Suspense fallback={<div>Loading...</div>}>
        <Component1 />
        <Component2 />
        <Component3 />
      </Suspense>
    </div>
  );
};

export default App;

В приведенном выше коде у нас есть три компонента, которые лениво загружаются с помощью функции React.lazy. Компоненты заключены в компонент React.Suspense с резервным компонентом, который отображается во время загрузки компонентов.

Когда вы запустите приведенный выше код, вы заметите, что во время загрузки компонентов отображается сообщение Loading.... После загрузки компонентов они визуализируются и отображаются на странице.

Улучшенный рендеринг на стороне сервера:

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

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

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

Вот пример того, как использовать автоматическую пакетную обработку обновлений состояния в React 18:

import React, { useState } from 'react';

const App = () => {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1);
    setCount(count + 1);
    setCount(count + 1);
  };

  console.log('count:', count);

  return (
    <div>
      <h1>My App</h1>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Increment</button>
    </div>
  );
};

export default App;

В приведенном выше коде у нас есть простой пример компонента React, который использует автоматическую пакетную обработку обновлений состояния. В компоненте есть кнопка, которая быстро обновляет состояние count три раза подряд.

Когда вы нажмете кнопку, вы заметите, что оператор console.log отображает только конечное состояние переменной count, то есть 3. Это указывает на то, что React сгруппировал три обновления состояния вместе и выполнил только один повторный рендеринг с окончательным состоянием.

Автоматическая пакетная обработка обновлений состояния может значительно повысить производительность приложений React за счет уменьшения количества повторных рендерингов, происходящих из-за обновлений состояния. Однако важно отметить, что могут быть случаи, когда вам нужно отключить автоматическую пакетную обработку и выполнить ручную пакетную обработку обновлений состояния. Вы можете сделать это, вызвав метод ReactDOM.unstable_batchedUpdates, чтобы вручную сгруппировать несколько обновлений состояния вместе.

Улучшенный рендеринг на стороне сервера:

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

import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './App';

const html = renderToString(<App />);
console.log(html);

В приведенном выше коде у нас есть пример рендеринга на стороне сервера в React 18. Функция renderToString используется для рендеринга компонента App на сервере и возврата результирующего HTML.