Операции с элементами в JSX в Реакте
Здравствуйте. Делаю проект на Реакте. Появилась задача создать функцию принимающую JSX с какой-то разметкой (например как на первой иллюстрации). Функция должна обернуть детей элемента <section> в условный <aside>, а в элементы <p> поместить компоненты (вторая иллюстрация). Как это можно реализовать?
![]() В стандартном JS операции оборачивания и вставки элементов не вызывают трудностей. Но даже не представляю как это можно реализовать в логике Реакта. Придумал такой сложный сценарий: 1. Функция принимает не JSX, то строку с разметкой. 2. Строка превращается в HTML-коллекцию в которой дети <section> оборачиваются в условный <aside>. 3. Готовую коллекцию превращаю в объект JavaScript где описаны теги, атрибуты и дети каждого элемента. 4. Объект прогоняется через рекурсивную функцию которая создаёт JSX и по ходу в каждый <p> вставляет компонент Реакта. Такой сценарий мне не нравится потому что для решения такой простейшей задачи придется написать строчек 300 и подключить пару библиотек. |
JSX — это объект где в свойстве props есть массив children. Именно в нем содержатся данные о детях. Но дело в том, что JSX нельзя изменять.
|
Понял как нужно делать. Уже созданный JSX изменить нельзя, но можно его обойти и создавать копии элементов. Это делает функция React.cloneElement(). Она принимает элемент для клонирования, объект с его атрибутами и детей. Для создания элемента нужно использовать React.createElement(). Там почти такой же набор параметров: имя тега, его атрибуты и массив детей. Эти две функции решат задачу.
function App() { let markup = ( <section> <p /><p /> <footer /> </section> ); // Вставляемый компонент function Span() { return <span>Span elem</span> } // Рекурсивная функция принимает JSX и изменяет разметку. function enhanceMarkup(elem) { // Если тегом элемента является section, то обернуть его детей в <aside>. if(elem.type === 'section') { // Составлю массив детей элемента <section> let childrenArr = elem.props.children.map((child, i) => { return React.cloneElement( // Функция запускается рекурсивно чтобы при следующем запуске обработать <p> enhanceMarkup(child), {key: i} ); }); // Сделаю новый элемент <aside> куда помещу детей <section> let aside = React.createElement('aside', null, childrenArr); // Клонирую <section> и поставлю в качестве потомка <aside> return React.cloneElement(elem, elem.props, aside) } // Если тегом элемента является p, то поставить компонент <Span /> потомком if(elem.type === 'p') { // Клонирую элемент и поставлю компонент как ребёнка return React.cloneElement(elem, elem.props, <Span />) } // Возвратить неизменный elem если его тегом не является section или p (которые обрабатываются и возвращаются в коде выше). return elem; } // Изменить и вернуть новую разметку markup return enhanceMarkup(markup) } |
Часовой пояс GMT +3, время: 23:49. |