React 18: что поменялось

в 7:01, , рубрики: javascript, React, web-разработка, новая версия
image

React — одна из самых популярных JavaScript-библиотек для создания пользовательских интерфейсов. В её новой версии произошли значительные изменения, и сейчас я расскажу про самые важные.

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

Появились такие новые возможности, как приостановка (Suspense), потоковый серверный рендеринг и автоматическое пакетирование. Это позволяет одномоментно обновлять все изменения состояний, произошедшие во время выполнения асинхронной операции.

Меня зовут Игорь Крамарь, я сеньор фронтенд-разработчик в команде «Купол Т1» и работаю с React уже несколько лет. Сегодня я расскажу вам про самые-самые важные изменения в этой программе.

Concurrent Mode

Самое существенное обновление, которое появилось в React 18, — конкурентный режим (Concurrent Mode). Это новый механизм, с помощью которого можно готовить несколько версий пользовательского интерфейса одновременно. Он предназначен для улучшения производительности и быстродействия приложений, особенно в случаях, когда рендеринг компонентов занимает много времени. В своей внутренней реализации React в этом режиме использует сложные приёмы, такие, как приоритетные очереди и многократная буферизация.

Рассмотрим, что такое конкурентный режим, как он работает и как его использовать на практике.

Что такое конкурентный режим?

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

Как работает конкурентный режим?

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

Все элементы, присутствующие на экране, система представляет в виде древовидной структуры — дерева компонентов DOM (объектная модель документа). Конкурентный рендерер в фоновом режиме одновременно создаёт ещё одну версию дерева в дополнение к основной.

Сравнение этих двух деревьев даёт понимание, какие элементы нужно обновить, а какие можно оставить в прежнем виде. Concurrent Mode внедряет изменения в рендер и разрешает разделить (или приостановить) какие-то обновления, уменьшить блокировки UI, чтобы у нас было более эффективное взаимодействие с интерфейсом. После сравнения предыдущего и текущего состояний компонентов дерева и определения изменений происходит отрисовка.

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

Как включить конкурентный режим?

В React 18 появилась новая функция — createRoot(), которая предоставляет возможность создавать корневой компонент в конкурентном режиме. Для этого нужно передать флаг `concurrent: true` вторым аргументом при создании корневого компонента:

import { createRoot } from 'react-dom';

const root = document.getElementById('root');

createRoot(root, { concurrent: true }).render(<App />);

Теперь приложение будет работать в конкурентном режиме.

Для использования конкурентного режима нужно создать корневой компонент с флагом concurrent: true и использовать хук useTransition() или функцию lazy()

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

Разделение длинного процесса на части

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

function LongProcess() {
  // Длинный процесс
  return <div>Long Process</div>;
}

Чтобы разбить этот процесс на части, мы можем использовать хук useTransition():

import { useTransition } from 'react';

function LongProcess() {
  const [isPending, startTransition] = useTransition();

  function process() {
    // Длинный процесс
  }

  return (
    <div>
      {isPending ? 'Loading...' : 'Long Process'}
      <button onClick={() => startTransition(process)}>Start</button>
    </div>
  );
}

Хук useTransition() возвращает массив с двумя элементами: isPending и startTransition(). isPending — это булевое значение, которое указывает, выполняется ли в данный момент процесс или нет. startTransition() — это функция, которую мы вызываем, чтобы начать выполнение процесса.

Отложенная загрузка

Конкурентный режим также может использоваться для отложенной загрузки компонентов. Для этого нужно использовать функцию lazy():

import { lazy, Suspense } from 'react';

const LazyComponent = lazy(() => import('./LazyComponent'));

function App() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <LazyComponent />
      </Suspense>
    </div>
  );
}

Функция lazy() принимает функцию, которая возвращает промис с компонентом. Когда компонент готов, он будет отображён. В противном случае будет отображён fallback-компонент.

Как на практике применяется конкурентный режим

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

Например, в нашей компании я работаю над проектом «Купол-Администрирование». Это приложение, которое относится к сфере администрирования и безопасности IT-систем. Мы выводим на единый экран всю информацию, получаемую из различного оборудования, которое входит в сеть компании. Каждое такое устройство имеет свою админ-панель, где можно смотреть и изменять различные параметры. И вот все эти данные в виде сложных форм и таблиц могут аккумулироваться системой «Купол-Администрирование», где их нужно принимать, менять и отрисовывать.

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

Другой пример — это CRM-система для управления клиентами, в которой крутится большой массив данных. Concurrent Mode помогает более плавно отображать информацию о клиентах и их заказах, даже если система обрабатывает данные десятков тысяч клиентов. Система быстро и гладко обеспечивает отрисовку данных. Это улучшает продуктивность сотрудников, потому что не приходится ждать обновления экрана.

Аналогичная польза от этого режима может быть в интерактивных приложениях, где одновременно работает много человек. Например, в «интерактивной доске» Miro могут работать 15, 30 или даже 50 сотрудников, которые одновременно что-то изменяют, передвигают стикеры, рисуют стрелки, добавляют записи. Все они взаимодействуют с сервером, и все изменения должны быстро и одновременно отображаться у каждого участника. Механизм конкурентного режима даёт возможность работать без задержек и лагов.

Как понять, что вам надо использовать Concurrent Mode

Чтобы оценить востребованность такого режима в приложении, надо посмотреть на объём данных, которые оно получает с backend-сервера. Если это, условно говоря, тысячи сущностей, список из тысяч сложных элементов, которые являются объектами со своими свойствами, подобъектами, то пользователи могут столкнуться с задержками при взаимодействии, отрисовке. Конкурентный режим может решить эту проблему, если от бизнеса есть требования к производительности.

В общем, Concurrent Mode — это новый мощный инструмент в React, и большинство новых функций построено с учётом его преимуществ.

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

Автоматический батчинг обновления состояний для асинхронных операций

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

Как работает автоматический батчинг?

Он собирает все обновления состояний, произошедших во время выполнения асинхронной операции, и применяет их одним общим обновлением после завершения операции. Это избавляет от множественных перерисовок компонентов и улучшает производительность приложения. Для использования автоматического батчинга нужно использовать функции setState() или useReducer() внутри асинхронных операций, таких, как setTimeout() или fetch().

Рассмотрим несколько примеров кода, чтобы понять, как использовать автоматический батчинг на практике.

Использование setState() внутри setTimeout()

Пример, когда мы используем setState() внутри setTimeout(). В этом случае React автоматически батчит обновления состояний, произошедшие во время выполнения setTimeout():

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

  useEffect(() => {
    setTimeout(() => {
      setCount(count + 1);
      setCount(count + 1);
    }, 1000);
  }, [count]);

  return <div>Count: {count}</div>;
}

В этом примере мы используем setTimeout() для установки двух обновлений состояний. Но благодаря автоматическому батчингу React применит их одним общим обновлением после завершения setTimeout().

Использование fetch()

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

function App() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/todos/1')
      .then(response => response.json())
      .then(json => setData(json));
  }, []);

  return <div>{data ? data.title : 'Loading...'}</div>;
}

Благодаря автоматическому батчингу React применит это обновление состояния одним общим обновлением после завершения fetch().

Хук useDeferredValue

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

Как работает useDeferredValue?

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

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

Рассмотрим несколько примеров кода, чтобы понять, как использовать useDeferredValue на практике.

Использование useDeferredValue с useState()

Пример, когда мы используем useDeferredValue с useState(). В этом случае мы откладываем обновление состояния до момента, когда пользователь закончит вводить текст в поле ввода:

function App() {
  const [text, setText] = useState('');
  const deferredText = useDeferredValue(text, { timeoutMs: 1000 });

  function handleChange(event) {
    setText(event.target.value);
  }

  return (
    <div>
      <input type="text" value={text} onChange={handleChange} />
      <div>Deferred text: {deferredText}</div>
    </div>
  );
}

В этом примере мы используем useDeferredValue с useState() для отложенного обновления значения состояния text. Мы также передаём опцию timeoutMs: 1000, чтобы задать время задержки в миллисекундах перед обновлением значения.

Использование useDeferredValue с useReducer()

Пример, когда мы используем useDeferredValue с useReducer(). В этом случае мы откладываем обновление состояния до момента, когда пользователь закончит перетаскивать элементы списка:

function reducer(state, action) {
  switch (action.type) {
    case 'drag':
      return { ...state, draggedItem: action.payload };
    case 'drop':
      return { ...state, items: action.payload };
    default:
      return state;
  }
}

function App() {
  const [state, dispatch] = useReducer(reducer, {
    items: ['Item 1', 'Item 2', 'Item 3'],
    draggedItem: null,
  });

  const deferredState = useDeferredValue(state, { timeoutMs: 1000 });

  function handleDragStart(event, item) {
    dispatch({ type: 'drag', payload: item });
  }

  function handleDrop(event) {
    event.preventDefault();
    const newItems = state.items.filter(i => i !== state.draggedItem);
    newItems.splice(event.target.dataset.index, 0, state.draggedItem);
    dispatch({ type: 'drop', payload: newItems });
  }

  return (
    <ul>
      {deferredState.items.map((item, index) => (
        <li
          key={item}
          draggable
          onDragStart={event => handleDragStart(event, item)}
          onDrop={handleDrop}
          data-index={index}
        >
          {item}
        </li>
      ))}
    </ul>
  );
}

В этом примере мы используем useDeferredValue с useReducer() для отложенного обновления значения состояния state. Мы также передаём опцию timeoutMs: 1000, чтобы задать время задержки в миллисекундах перед обновлением значения.

Улучшения SSR в React 18

React 18 представляет несколько изменений для серверного рендеринга (SSR), которые могут значительно улучшить производительность. Предварительный рендеринг, использование Suspense для SSR и useOpaqueIdentifier — это только некоторые из новых функций, которые могут быть полезны при работе с SSR.

Рассмотрим эти изменения и приведём примеры кода для их использования.

Предварительный рендеринг

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

Это может значительно сократить время загрузки страницы и улучшить SEO.

Для использования предварительного рендеринга в React 18 вы можете использовать новый метод — renderToNodeStream().

Вот пример кода:

import { renderToNodeStream } from 'react-dom/server';

app.get('/', (req, res) => {
  const stream = renderToNodeStream(<App />);
  res.write('<!DOCTYPE html>');
  res.write('<html>');
  res.write('<head>');
  res.write('<title>React 18 SSR</title>');
  res.write('</head>');
  res.write('<body>');
  stream.pipe(res, { end: false });
  stream.on('end', () => {
    res.write('</body>');
    res.write('</html>');
    res.end();
  });
});

Новая функция серверного рендеринга в React 18 renderToNodeStream() используется здесь для рендеринга компонента <App /> на сервере и передачи его в потоковый ответ. Мы также добавляем базовую HTML-разметку и закрываем её после того, как потоковый ответ завершится.

RenderToPipeableStream возвращает подключаемый поток Node.js. Эта функция полностью интегрируется с функцией Suspense и разделением кода через React.lazy. В отличие от renderToNodeStream renderToPipeableStream предоставляет более гибкий и оптимизированный подход к серверному рендерингу, учитывая новые возможности React 18.

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

Пример использования renderToPipeableStream:

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

const stream = renderToPipeableStream(<App />);

stream.pipe(res); // где 'res' является объектом ответа сервера

В этом примере мы импортируем функцию renderToPipeableStream из react-dom/server и используем её для рендеринга нашего главного приложения App. Затем мы направляем результат в ответ сервера с помощью метода pipe.

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

Использование Suspense для SSR

React 18 также включает в себя улучшения для использования Suspense в SSR. Можно использовать Suspense для ожидания загрузки данных на сервере и отображения заглушки до того, как данные будут доступны.

Вот пример кода:

import { Suspense } from 'react';
import { renderToString } from 'react-dom/server';

function App() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <AsyncComponent />
      </Suspense>
    </div>
  );
}

app.get('/', async (req, res) => {
  const data = await fetchData();
  const html = renderToString(<App data={data} />);
  res.send(html);
});

В этом примере мы используем Suspense для ожидания загрузки данных на сервере перед рендерингом компонента <AsyncComponent />. Мы также добавляем заглушку Loading… для отображения до того, как данные будут доступны.

Использование useOpaqueIdentifier для SSR

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

Вот пример кода:

import { useOpaqueIdentifier } from 'react';

function App() {
  const id = useOpaqueIdentifier();
  return (
    <div>
      <h1>Component with ID: {id}</h1>
    </div>
  );
}

app.get('/', async (req, res) => {
  const html = renderToString(<App />);
  res.send(html);
});

В этом примере мы используем useOpaqueIdentifier() для генерации уникального идентификатора на сервере при рендеринге компонента <App />. Мы также отправляем сгенерированный идентификатор в HTML-коде, который будет использоваться на клиенте.

Какие основные преимущества SSR могут повлиять на производительность и пользовательский опыт веб-приложений?

Быстрое время загрузки: SSR обновляет только те части HTML, которые требуют обновления, что обеспечивает быстрое переключение между страницами и очень быстрый First Contentful Paint (FCP). Даже пользователи с медленными интернет-соединениями или устаревшими устройствами могут немедленно взаимодействовать с вашими веб-страницами.

Лёгкость индексации: Индексация сайтов на SSR гораздо проще для поисковых систем, чем сайтов, отрисованных на стороне клиента. Содержимое отображается до загрузки страницы, поэтому им не нужно запускать JavaScript для чтения и индексации.

Идеально подходит для статических веб-сайтов: SSR отлично подходит для статических веб-страниц, так как быстрее предварительно отрисовывать статическую (или неизменную) страницу на сервере, прежде чем отправлять её клиенту.

SSR обновляет только те части HTML, которые требуют обновления, что обеспечивает быстрое переключение между страницами и очень быстрый First Contentful Paint (FCP) даже для пользователей с очень медленными интернет-соединениями или устаревшими устройствами.

Кроме того, индексация сайтов на SSR гораздо проще для поисковых систем, чем сайтов, отрисованных на стороне клиента. Содержимое отображается до загрузки страницы, поэтому им не нужно запускать JavaScript для чтения и индексации. Кроме всего вышеперечисленного, SSR хорошо подходит для статических веб-страниц, так как времени на отрисовывание неизменных страниц на сервере перед отправкой клиенту с его помощью уходит гораздо меньше.

Хук useId

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

Вот пример кода:

import { useId } from 'react';

function App() {
  const inputId = useId();
  const labelId = useId();
  return (
    <div>
      <label htmlFor={inputId}>Name:</label>
      <input id={inputId} type="text" />
    </div>
  );
}

app.get('/', async (req, res) => {
  const html = renderToString(<App />);
  res.send(html);
});

В этом примере мы используем useId() для генерации уникальных идентификаторов для элементов <input> и <label>. Мы также используем htmlFor для связывания метки с полем ввода.

Вы можете передать префикс в качестве аргумента useId(), чтобы создать уникальные идентификаторы с определённым префиксом:

const inputId = useId('input');
const labelId = useId('label');

В этом примере мы создаём уникальные идентификаторы с префиксами <input> и <label>.

Хук useSyncExternalStore

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

Вот пример кода:

import { useSyncExternalStore } from 'react';

function App() {
  const [count, setCount] = useState(0);
  useSyncExternalStore('count', count, setCount);

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

В этом примере мы используем useSyncExternalStore() для синхронизации состояния count с внешним хранилищем данных. Мы передаём имя переменной count, значение count и функцию setCount для обновления значения count.

Вы можете использовать useSyncExternalStore() для синхронизации любых переменных или объектов:

const [user, setUser] = useState({ name: 'John', age: 30 });
useSyncExternalStore('user', user, setUser);

В этом примере мы синхронизируем объект user с внешним хранилищем данных.

Вы также можете использовать useSyncExternalStore() для обмена данными между компонентами:

// Component A
const [value, setValue] = useState('');
useSyncExternalStore('value', value, setValue);

// Component B
const [value, setValue] = useState('');
useSyncExternalStore('value', value, setValue);

В этом примере мы синхронизируем значение value между двумя компонентами.

Мы рекомендуем использовать встроенные хуки управления состоянием React, такие, как useState и useReducer, для управления состоянием. Однако есть сценарии, в которых useSyncExternalStore тоже имеет смысл:

  • Интеграция React с существующим не-React-кодом.
  • Подписка на API-браузер (например, на веб-уведомления или свойство navigator.onLine).

Хук useInsertionEffect

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

Вот пример кода:

import { useInsertionEffect } from 'react';

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

  useInsertionEffect(() => {
    console.log('Component has been mounted');
  });

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

В этом примере мы используем useInsertionEffect() и передаём функцию, которая будет выполнена после монтирования компонента.

Вы можете использовать useInsertionEffect() для выполнения любых действий, которые должны быть выполнены после монтирования компонента:

useInsertionEffect(() => {
  // Выполнить запрос к API
  // Загрузить данные в состояние компонента
  // И т. д.
});

Вы также можете использовать useInsertionEffect() для выполнения действий перед каждым рендерингом компонента:

useInsertionEffect(() => {
  console.log('Component will be re-rendered');
}, [count]);

В этом примере мы передаём зависимость [count], чтобы эффект был выполнен только перед каждым рендерингом компонента, если значение count изменилось.

Что дальше?

Сейчас идёт работа над React Optimizing Compiler (ROC) — это новый инструмент, который поможет оптимизировать производительность приложений, ускоряя процесс рендеринга компонентов и уменьшая время загрузки страницы. Этот компилятор автоматически генерирует эквивалент вызовов useMemo и useCallback, тем самым минимизируя стоимость повторного рендеринга, не теряя при этом основной модели программирования React.
ROC использует различные техники оптимизации: сжатие кода, удаление неиспользуемых зависимостей и динамическую загрузку компонентов. Это позволяет уменьшить размер приложения и ускорить его работу на мобильных устройствах.

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

ROC будет доступен как часть React Developer Tools, которые помогают разработчикам отлаживать и оптимизировать приложения.

В целом React Optimizing Compiler — это мощный инструмент для оптимизации производительности приложений на React. Он поможет ускорить работу приложений и улучшить пользовательский опыт. Разработчики могут использовать ROC для создания быстрых и эффективных приложений на React.

В будущих версиях React-разработчики обещают:

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

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

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

Кроме того, в React будут добавлены новые возможности для работы с изображениями, например, компонент Picture для адаптивной загрузки изображений в зависимости от размера экрана устройства пользователя. Также будет добавлена поддержка WebP-формата изображений, который имеет более высокую степень сжатия и быстрее загружается на мобильных устройствах.

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

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

Как это работает? Когда компонент находится вне экрана, он не рендерится. Вместо этого Offscreen создаёт скрытую область, где компонент может быть рендерен без отображения на экране. Когда компонент становится видимым, он быстро отображается на экране.

Offscreen позволяет улучшить производительность приложений, особенно на мобильных устройствах. Он также может быть полезен для компонентов, которые не нуждаются в постоянном обновлении, но всё ещё должны быть доступны на странице.

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

Offscreen поможет ускорить работу приложений и улучшить пользовательский опыт.

Разработчики могут использовать Offscreen для создания быстрых и эффективных приложений на React.

Server Components — новый подход к созданию React-приложений, который будет введён в будущих версиях библиотеки. Благодаря ему можно разделять компоненты на две части: клиентскую и серверную. Клиентская часть отвечает за отображение компонента на экране, а серверная — за его предварительную обработку на стороне сервера.

Как это работает? Когда пользователь запрашивает страницу, серверная часть компонента рендерится на стороне сервера и отправляется пользователю в виде готовой HTML-страницы.

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

Server Components позволяют улучшить производительность приложений, особенно при работе с большими объёмами данных и сложными компонентами. Они могут быть полезны также для создания быстрых и отзывчивых приложений на медленных устройствах или с плохим соединением.

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

Server Components будут доступны как часть React Developer Tools и будут поддерживаться браузерами Chrome и Firefox. Они также будут интегрированы с популярными фреймворками и библиотеками, такими, как Next.js и Gatsby.

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

Как это работает? Transition Tracing записывает все изменения состояний компонентов и создаёт диаграмму времени выполнения, которая показывает, какие компоненты были обновлены и какие анимации были запущены в процессе перехода. Это даёт возможность разработчикам быстро выявлять проблемы с производительностью и оптимизировать код для улучшения пользовательского опыта.

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

Transition Tracing может быть особенно полезен для создания сложных и интерактивных пользовательских интерфейсов, которые требуют много анимаций и переходов. Он также может быть полезен для создания приложений, которые должны работать на медленных устройствах или с плохим соединением.

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

Автор: Игорь Крамарь

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js