React v16.2.0: улучшенная поддержка фрагментов
Ноябрь 28, 2017 Клемент Хонг
React 16.2 теперь доступен! Самым большим дополнением является улучшенная поддержка возврата нескольких дочерних элементов из метода отрисовки(рендеринга) компонента. Мы называем эту возможность фрагментами.
Фрагменты выглядят как пустые теги JSX. Они позволяют группировать список дочерних элементов без добавления дополнительных узлов в DOM:
render() {
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
);
}
Эта потрясающая новая функция стала возможной благодаря дополнениям как к React, так и к JSX.
Общим примером является компонент, который возвращает список дочерних элементов. Рассмотрим данный пример HTML:
Какой-то текст.
<h2>Первый заголовок</h2>
Еще текст.
<h2>Второй заголовок</h2>
Еще больше текста.
До версии 16 единственным способом достичь этого в React было обертывание
потомков в дополнительный элемент, обычно div
или span
:
render() {
return (
// Дополнительный элемент div :(
<div>
Какой-то текст.
<h2>Первый заголовок </h2>
Еще текст.
<h2>Второй заголовок </h2>
Еще больше текста.
</div>
);
}
Чтобы устранить это ограничение, в React 16.0 была добавлена поддержка возврата массива элементов из метода отрисовки компонента. Вместо того, чтобы обертывать дочерние элементы в элемент DOM, вы можете поместить их в массив:
render() {
return [
"Какой-то текст.",
<h2 key="heading-1">Первый заголовок</h2>,
"Еще текст.",
<h2 key="heading-2">Второй заголовок</h2>,
"Еще больше текста."
];
}
Однако такой подход имеет некоторые значительные отличия от обычного JSX:
- Потомки в массиве должны быть разделены запятыми.
- У потомков в массиве должен быть ключ, предотвращающий React предупреждения в консоли.
- Строки должны быть заключены в кавычки.
Чтобы обеспечить наиболее совместимую разработку фрагментов, React теперь предоставляет
первоклассный компонент Fragment
, который можно использовать вместо массивов.
render() {
return (
<Fragment>
Какой-то текст.
<h2>Первый заголовок</h2>
Еще текст.
<h2>Второй заголовок</h2>
Еще больше текста.
</Fragment>
);
}
Вы можете использовать <Fragment/>
так же, как используете любой другой элемент,
не изменяя способ написания JSX. Никаких запятых, никаких ключей, никаких кавычек.
Компонент Fragment
доступен в главном объекте React
:
const Fragment = React.Fragment;
<Fragment>
<ChildA />
<ChildB />
<ChildC />
</Fragment>
// Так тоже работает
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
Фрагменты - это общий паттерн в нашей кодовой базе в Facebook. Мы ожидаем, что они будут широко приняты другими командами. Чтобы сделать опыт разработки максимально удобным, мы добавляем синтаксическую поддержку для фрагментов в JSX:
render() {
return (
<>
Какой-то текст.
<h2>Первый заголовок</h2>
Еще текст.
<h2>Второй заголовок</h2>
Еще больше текста.
</>
);
}
В React это является синтаксическим сахаром для элемента <React.Fragment/>
из примера в предыдущем разделе. (Не-React фреймворки, которые
используют JSX, могут компилировать во что-то другое).
Синтаксис фрагментов в JSX был вдохновлен изящным предшественником, таким как
конструктор XMLList() <> </>
в E4X. Использование
пары пустых тегов предназначено для того, чтобы обозначить, что в DOM не
будет добавлено реального элемента.
Фрагменты с ключами
Обратите внимание, что синтаксис <> </>
не принимает атрибуты, включая ключи.
Если вам нужен фрагмент с ключом, вы можете напрямую использовать
<Fragment/>
. Вариант использования для этого - маппинг коллекции в массив
фрагментов - например, для создания списка описания:
function Glossary(props) {
return (
<dl>
{props.items.map(item => (
// Без ключа `key`, React выдаст предупреждение в консоль
<Fragment key={item.id}>
<dt>{item.term}</dt>
<dd>{item.description}</dd>
</Fragment>
))}
</dl>
);
}
key
- это единственный атрибут, который может быть передан Fragment
.
В будущем мы можем добавить поддержку дополнительных атрибутов,
таких как обработчики событий.
Демо
Вы можете поэкспериментировать с JSX синтаксисом фрагментов с помощью данного CodePen .
Поддержка синтаксиса фрагментов в JSX будет зависеть от инструментов, которые вы используете для построения своего приложения. Пожалуйста, будьте терпеливы, поскольку сообщество JSX работает над принятием нового синтаксиса. Мы тесно сотрудничаем с разработчиками самых популярных проектов:
Create React App
Экспериментальная поддержка синтаксиса фрагментов будет добавлена в приложение Create React. Устойчивый выпуск может занять немного больше времени, так как мы ожидаем одобрения другими проектами.
Babel
Поддержка фрагментов JSX доступна в Babel v7.0.0-beta и выше! Если вы уже на Babel 7, просто обновите последнюю версию Babel и плагина преобразования:
# для пользователей yarn
yarn upgrade @babel/core @babel/plugin-transform-react-jsx
# для пользователей npm
npm update @babel/core @babel/plugin-transform-react-jsx
Или, если вы используете react-present :
# для пользователей yarn
yarn upgrade @babel/core @babel/preset-react
# для пользователей npm
npm update @babel/core @babel/preset-react
Обратите внимание, что Babel 7 технически все еще в бета-версии, но стабильный релиз уже скоро.
К сожалению отсутствует поддержка для Babel 6.x, и в настоящее время нет планов по обратной совместимости.
Babel с Webpack
Если вы используете Babel с Webpack, дополнительных шагов не требуется,
потому что babel-loader
будет использовать установленную вами версию Babel.
Babel c другими фреймворками
Если вы используете JSX с не-React фреймворком, например Inferno или Preact,
есть опция pragma
, доступная в babel-plugin-transform-react-jsx
, которая настраивает
компилятор Babel для работы с синтаксисом <> </>
.
TypeScript
TypeScript имеет полную поддержку синтаксиса фрагментов! Обновитесь до версии 2.6.2. (Обратите внимание, что это важно, даже если вы уже на версии 2.6.1, так как поддержка была добавлена как релиз патча в 2.6.2.)
Проведите апгрейд до последнего TypeScript с помощью команды:
# для пользователей yarn
yarn upgrade typescript
# для пользователей npm
npm update typescript
Flow
Flow поддерживает фрагменты JSX начиная с ! Просто запустите:
# для пользователей yarn
yarn upgrade flow-bin
# для пользователей npm
npm update flow-bin
чтобы обновить Flow до последней версии.
Prettier
добавляет поддержку фрагментов в своем .
ESLint
JSX фрагменты поддерживаются ESLint 3.x, когда он используются вместе с :
# для пользователей yarn
yarn add [email protected] [email protected]
# для пользователей npm
npm install [email protected] [email protected]
или если он у вас уже есть, то сделайте апгрейд:
# для пользователей yarn
yarn upgrade [email protected] [email protected]
# для пользователей npm
npm update [email protected] [email protected]
Убедитесь, что у вас есть следующая строка внутри вашего файла
конфигурации .eslintrc
:
"parser": "babel-eslint"
Это всё!
Обратите внимание, что babel-eslint
официально не поддерживается ESLint.
Мы рассмотрим возможность добавления фрагментов к ESLint 4.x в
ближайшие недели (см.
).
Поддержка редактором
Может потребоваться некоторое время для поддержки синтаксиса фрагментов в текстовом редакторе. Будьте терпеливы, поскольку сообщество работает над принятием последних изменений. Тем временем вы можете увидеть ошибки или некорректную подсветку, если ваш редактор еще не поддерживает синтаксис фрагментов. Как правило, эти ошибки можно безопасно игнорировать.
Поддержка синтаксиса TypeScript редактором
Если вы пользователь TypeScript - отличная новость! Поддержка редактором фрагментов JSX уже доступна в Visual Studio 2015, Visual Studio 2017, Visual Studio Code и Sublime Text с помощью функции Package Control.
Другие инструменты
Для других инструментов ознакомьтесь с соответствующей документацией, чтобы проверить наличие поддержки. Однако, если вы заблокированы своей инструментальной базой, вы всегда можете начать с использования компонента <Fragment> и позже выполнить codemod, чтобы заменить его сокращенным синтаксисом, когда соответствующая поддержка будет доступна.
React v16.2.0 доступен в реестре npm.
Чтобы установить React 16, запустите:
# для пользователей yarn
yarn add [email protected]^16.2.0 [email protected]^16.2.0
# для пользователей npm
npm install --save [email protected]^16.2.0 [email protected]^16.2.0
Мы также предоставляем сборки UMD React-а через CDN:
<script crossorigin src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>
Обратитесь к документации для подробных инструкций по установке .
React
- Добавление
Fragment
как именованный export в React. ( в ) - Поддержка экспериментальных типов Call/Return в утилитах React.Children. ( в )
React-DOM
- Исправление радиокнопок, которые не выбираются при использовании нескольких списков радиокнопок. ( в )
- Исправление радиокнопок, не принимающих событие
onChange
в некоторых случаях. ( в )
React Test Renderer
- Исправлен баг слишком раннего срабатывания коллбэка метода setState(), когда он вызывается из метода componentWillMount. ( в )
React Reconciler
- Представлен response-reconciler/reflection с утилитами, полезными для кастомной отрисовки. ( в )
Внутренние изменения
Многие тесты были переписаны в отличие от публичного API. Большое спасибо всем, кто внес свой вклад!
Этот выпуск стал возможным благодаря нашим open source участникам. Большое спасибо всем, кто создавал issue, внес свой вклад в обсуждениях синтаксиса, проверял PR-ы, добавил поддержку фрагментов JSX в сторонние библиотеки и многое другое!
Особая благодарность командам TypeScript и Flow, а также команде сопровождения Babel, которые помогли реализовать инструментальную поддержку нового синтаксиса.
Благодарим Gajus Kuizinas и других участников, которые прототипировали
компонент Fragment
в open source.