React v16.6.0: lazy, memo и contextType
Сегодня мы выпускаем React 16.6 с несколькими новыми удобными возможностями: версию PureComponent/shouldComponentUpdate для функциональных компонентов, способ разделения кода при помощи Suspense и упрощённый доступ к контексту из классовых компонентов.
Полный список изменений описан далее в посте.
React.memo
Классовые компоненты при помощи PureComponent
или shouldComponentUpdate
могут останавливать рендеринг, если пропсы не изменились. Теперь это доступно и в функциональных компонентах, если обернуть их в React.memo
.
const MyComponent = React.memo(function MyComponent(props) {
/* повторный рендер пройдёт только при изменении пропсов */
});
React.lazy
: разделение кода при помощи Suspense
Возможно, вы уже видели доклад Дэна о React Suspense(задержке) на JSConf Iceland. Теперь можно использовать компонент Suspense для разделения кода — нужно просто обернуть динамический импорт в React.lazy()
.
import React, {lazy, Suspense} from 'react';
const OtherComponent = lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<Suspense fallback={<div>Загрузка...</div>}>
<OtherComponent />
</Suspense>
);
}
Компонент Suspense также даст возможность авторам библиотек в дальнейшем реализовать подгрузку данных с задержкой.
Примечание: эта функциональность пока не доступна для серверного рендеринга. Задержка будет добавлена в будущих релизах.
static contextType
В React 16.3 мы представили официальный API для контекста, который заменит устаревший.
const MyContext = React.createContext();
Мы учли отзывы про сложности использования нового API рендер-пропсов в классовых компонентах. Поэтому добавили удобный API для получения значений контекста из классовых компонентов.
class MyClass extends React.Component {
static contextType = MyContext;
componentDidMount() {
let value = this.context;
/* выполнить побочный эффект при монтировании, взяв значение из MyContext */
}
componentDidUpdate() {
let value = this.context;
/* ... */
}
componentWillUnmount() {
let value = this.context;
/* ... */
}
render() {
let value = this.context;
/* отрендерить что-нибудь, основываясь на значении из контекста */
}
}
static getDerivedStateFromError()
React 16 впервые представил предохранители — механизм обработки ошибок, выброшенных при рендере. У нас уже есть метод жизненного цикла, вызываемый после возникновения ошибок, — componentDidCatch
— он отлично подходит для отправки логов ошибок на сервер. Плюс к этому, с его помощью можно вызвать setState
и показать другой UI.
До вызова этого метода мы рендерим null
в точке дерева, где произошла ошибка. Иногда родительские компоненты бывают не готовы к исчезновению рефов на дочерние компоненты и ломаются. Восстановиться после ошибки на сервере также нельзя, потому что Did
-методы жизненного цикла при серверном рендере не вызываются.
Мы добавили новый метод для рендера запасного UI до момента, пока не завершится полный рендер. Подробнее о getDerivedStateFromError()
вы можете почитать в документации.
Примечание:
getDerivedStateFromError()
пока что не работает в серверном рендере. Мы выпустили его в таком сыром виде, чтобы вы пораньше с ним освоились и подготовились к релизу, в котором метод заработает и на сервере.
Устаревшие API в StrictMode
В версии 16.3 мы представили компонент StrictMode
, который позволяет выводить предупреждения, если в коде используются конструкции, которые в будущем могут вызвать проблемы.
Мы добавили ещё два API в список устаревших API StrictMode
. Не беспокойтесь: если вы не используете StrictMode
, эти предупреждения у вас не появятся.
- ReactDOM.findDOMNode() — этот API-метод часто неправильно понимают, и в большинстве случаев он не нужен. К тому же, он может сильно тормозить в React 16. В документации мы описали, чем можно его заменить.
- Legacy Context — contextTypes и getChildContext слегка замедляют React и добавляют ему лишней громоздкости. Так что мы настоятельно рекомендуем вам перейти на новый API контекста. Мы надеемся, что новый API
contextType
упростит вам переход.
Если у вас возникнут трудности с обновлением, пожалуйста, дайте нам знать.
Установка
React v16.6.0 уже доступен в реестре npm.
Чтобы установить React 16 при помощи yarn, запустите:
yarn add react@^16.6.0 react-dom@^16.6.0
Чтобы установить React 16 при помощи npm, запустите:
npm install --save react@^16.6.0 react-dom@^16.6.0
Также мы даём возможность скачивать UMD-сборки React через CDN:
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
Подробнее об установке вы можете узнать в документации.
Список изменений
React
- Добавлен
React.memo()
в качестве альтернативыPureComponent
для функциональных компонентов. (@acdlite в #13748) - Добавлен
React.lazy()
для компонентов с разделением кода. (@acdlite в #13885) React.StrictMode
теперь предупреждает об устаревшем API контекста. (@bvaughn в #13760)React.StrictMode
теперь предупреждает оfindDOMNode
. (@sebmarkbage в #13841)unstable_AsyncMode
переименован вunstable_ConcurrentMode
. (@trueadm в #13732)unstable_Placeholder
переименован вSuspense
, аdelayMs
— вmaxDuration
. (@gaearon в #13799 и @sebmarkbage в #13922)
React DOM
- Добавлен более удобный способ подписки на контекст из классов —
contextType
. (@bvaughn в #13728) - Добавлен метод жизненного цикла для отлова ошибок в новом асинхронном серверном рендерере
getDerivedStateFromError
. (@bvaughn в #13746) - Теперь выводится предупреждение, когда вместо
<Context.Consumer>
используется<Context>
. (@trueadm в #13829) - Исправлен серый оверлей в iOS Safari. (@philipp-spiess в #13778)
- Исправлен баг, вызываемый перезаписью
window.event
в режиме разработки. (@sergei-startsev в #13697)
React DOM Server
- Добавлена поддержка
React.memo()
. (@alexmckenley в #13855) - Добавлена поддержка
contextType
. (@alexmckenley и @sebmarkbage в #13889)
Планировщик (экспериментально)
- Пакет переименован в
scheduler
. (@gaearon в #13683) - Добавлена поддержка продолжений, обёрнутых колбэков и уровней приоритета. (@acdlite в #13720 и #13842)
- Улучшен механизм запасного планировщика в среде без DOM. (@acdlite в #13740)
requestAnimationFrame
теперь принудительно выполняется в начале фрейма. (@acdlite в #13785)- Добавлена более тщательная проверка на наличие DOM. (@trueadm в #13731)
- Исправлены баги счётчика взамодействий. (@bvaughn в #13590)
- В пакет добавлена
envify
-трансформация кода. (@mridgway in #13766)