React использует прием делегирования событий и привязывает все события к объекту document
. Таким образом, достигается повышение производительности.
Но если на странице используется несколько версий React, микрофронтенды или часть функционала работает на jQuery, то возникают проблемы. Такое поведение ломает event.stopPropagation()
: если вложенное дерево остановило распространение (propagation) события, внешнее дерево все равно получит его.
Теперь все обработчики крепятся к корневому элементу, а не объекту document:
const rootNode = document.getElementById('root'); // <-- вот сюда
ReactDOM.render(<App />, rootNode);
Убрана оптимизация событий, которая более не актуальна в современных браузерах.
function handleChange(event) {
// это работает в 16 React только если добавить event.persist()
setData(data => ({
...data,
// This crashes in React 16 and earlier:
text: event.target.value
}));
}
Теперь такой код не будет валиться с ошибкой, и нет нужды писать event.persist()
Для обратной совместимости эта функция оставлена в качестве заглушки.
Было сделано некоторое количество небольших изменений. Эти изменения сближают React с поведением браузера.
onScroll
больше не всплывает, чтобы избежать текущей путаницы;onFocus
и onBlur
изменены “под капотом” на нативные focusin
и focusout
;onClickCapture
и другие Capture-события теперь используют браузерные обработчики событий.useEffect(() => {
// This is the effect itself.
return () => {
// This is its cleanup.
};
});
Раньше только функция эффекта запускалась асинхронно, а возвращаемая функция для очистки подписок запускалась синхронно. Теперь и функция очистки работает асинхронно, что улучшает производительность в случае перерисовки большого количества элементов.
Для синхронной работы, можно по-прежнему использовать useLayoutEffect()
, который остался незатронутым.
Это изменение довольно минорно, но повышает консистентность ошибок.
Если раньше нельзя было возвращать undefined
только в обычных компонентах, то теперь такая ошибка будет выбрасываться еще и в React.forwardRef
и React.memo
.
let Button = forwardRef(() => {
// We forgot to write return, so this component returns undefined.
// React 17 surfaces this as an error instead of ignoring it.
<button />;
});
let Button = memo(() => {
// We forgot to write return, so this component returns undefined.
// React 17 surfaces this as an error instead of ignoring it.
<button />;
});
Когда выбрасывается ошибка, браузер показывает stack trace с названиями функций и их местоположения. Довольно трудно по этому стеку вызовов понять, в каком месте и в каком компоненте была вызвана ошибка на самом деле.
Теперь спользуется новых механизм по генерации стека вызовов, что позволяет увидеть дерево React-компонентов, которое привело к ошибке, даже в production-среде.
Последнее изменение — это удаление некоторых внутренних экспортов, которые ранее были открыты наружу.
Конкурентность - это не функциональность, как таковая. Это новый закулисный механизм, который позволяет React подготавливать несколько версий пользовательского интерфейса одновременно.
React группирует несколько обновлений состояния в один повторный рендеринг для повышения производительности. В отсутствии автоматического пакетирования мы пакетировали только обновления внутри обработчиков событий React. Также и для промисов, setTimeout, чего не было в 17 версии.
// Теперь: обновления внутри setTimeout, промисах, нативных обработчиках событий или любые другие события - пакетируются
setTimeout(() => {
setCount(c => c + 1);
setFlag(f => !f);
// React выполнит только один пере-рендер в конце (это и есть пакетирование!)
}, 1000);
Batching работает по дефолту, но его можно отключить. Для этого используется функция flushSync.
import { flushSync } from 'react-dom';
flushSync(() => {
setCount(c => c + 1);
setFlag(f => !f);
});
Переход - это новая концепция в React для разграничения срочных и не срочных обновлений.
import { startTransition } from 'react';
// Срочно: Отобразить то что было введено пользователем
setInputValue(input);
// Любые изменения состояния внутри помечаются как переходные
startTransition(() => {
// Transition: Show the results
setSearchQuery(input);
});
Обновления, обернутые в startTransition, обрабатываются как не срочные и будут прерваны, если поступят более срочные обновления, такие как щелчки или нажатия клавиш.
useTransition
: хук для запуска переходов, включающий значение для отслеживания состояния ожидания.startTransition
: метод для запуска переходов, когда хук не может быть использован (прим. переводчика - в классовых компонентах).Переходы согласуются с конкурентным рендерингом, что позволяет прервать обновление.
Новое API теперь экспортируются из react-dom/client:
import React, { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { App } from './app';
const container = document.getElementById('app');
if (!container) {
throw new Error('Failed to find the root element');
}
const root = createRoot(container);
root.render(
<StrictMode>
<App />
</StrictMode>,
);
React получил новую бета-версию React 19. Это предварительная версия позволяет библиотекам адаптироваться к грядущим изменениям и подготовить совместимость перед официальным выпуском.
React теперь будет понимать, когда нужно вашу функцию/переменную/компонент мемоизировать, и вам не нужно думать, как и где побольше выиграть в производительности. Ручная мемоизация также остается.
Механизм предназначен для того, чтобы запомнить, что вы сделали на одном компоненте при переходе на другой. То есть, прыгая между табами или страницами, ваше состояние формы или чего-либо еще будет сохранено.
Вместо того, чтобы самостоятельно управлять состоянием во время выполнения асинхронных задач (например, при отправке формы или изменении данных), React 19 предоставляет более удобный способ обработки состояний с использованием Actions. Они позволяют автоматически обрабатывать состояния ожидания, ошибки, оптимистические обновления и выполнение последовательных запросов.
function ChangeName({ name, setName }) {
const [error, submitAction, isPending] = useActionState(
async (previousState, formData) => {
const error = await updateName(formData.get("name"));
if (error) {
return error;
}
redirect("/path");
return null;
},
null,
);
return (
<form action={submitAction}>
<input type="text" name="name" />
<button type="submit" disabled={isPending}>Update</button>
{error && <p>{error}</p>}
</form>
);
}
Помогает оптимистично отображать данные, пока идет асинхронный запрос.
function ChangeName({currentName, onUpdateName}) {
const [optimisticName, setOptimisticName] = useOptimistic(currentName);
const submitAction = async formData => {
const newName = formData.get("name");
setOptimisticName(newName);
const updatedName = await updateName(newName);
onUpdateName(updatedName);
};
return (
<form action={submitAction}>
<p>Your name is: {optimisticName}</p>
<p>
<label>Change Name:</label>
<input
type="text"
name="name"
disabled={currentName !== optimisticName}
/>
</p>
</form>
);
}
Позволяет читать ресурсы прямо во время рендеринга. Например, можно использовать Promise и обрабатывать его асинхронно, используя Suspense для отображения интерфейса загрузки.
import {use} from 'react';
function Comments({commentsPromise}) {
// `use` will suspend until the promise resolves.
const comments = use(commentsPromise);
return comments.map(comment => <p key={comment.id}>{comment}</p>);
}
function Page({commentsPromise}) {
// When `use` suspends in Comments,
// this Suspense boundary will be shown.
return (
<Suspense fallback={<div>Loading...</div>}>
<Comments commentsPromise={commentsPromise} />
</Suspense>
)
}
Предоставляют новые возможности предварительной обработки компонентов и выполнения асинхронных действий на стороне сервера. Это позволяет передавать данные между клиентом и сервером более эффективно и с минимальными затратами по времени.
ref
как проп: Поддержка передачи ref
напрямую в функциональные компоненты, что делает их более гибкими и исключает необходимость в forwardRef
.<Context>
как провайдер: Теперь можно использовать <Context>
непосредственно как провайдер, что упрощает настройку иерархии контекстов.<title>
, <meta>
и другими элементами из компонентов.Новые возможности и улучшения в React 19 Beta: обзор обновлений и оптимизация перехода