При работе с React лучше использовать многоразовые компоненты с помощью таких инструментов, как Bit, чтобы избежать необходимости переписывать их каждый раз. К тому же, приятно использовать компоненты, организованные в визуальной галерее, не так ли?
Постановка задачи
Попробуйте визуализировать несколько компонентов React подобным образом:
class ParentC extends React.Component { render() { return ( <ChildC /> <ChildC /> ) } } class ChildC extends React.Component { render() { return ( <h1> Child Component </h1> ) } }
или создать подобный список узлов:
class ChildComponent extends React.Component { render() { return ( <h1>Hello Child Component</h1> <h1>Hello Child Component</h1> ) } }
При использовании VS Code с расширениями поддержки JSX, появится предупреждение: “Родительские выражения JSX должны иметь один родительский элемент”.
Чтобы предупреждение исчезло, нужно добавить дополнительный тег div в качестве родительского элемента в разметку JSX.
class ParentC extends React.Component { render() { return ( <div> <ChildComponent /> <ChildComponent /> </div> ) } } class ChildComponent extends React.Component { render() { return ( <div> <h1>Hello Child Component</h1> <h1>Hello Child Component</h1> </div> ) } }
Проблема заключается в том, что использовать теги div немного неудобно. В HTML встречаются случаи, когда дополнительный div может деструктурировать DOM. Например, при использовании таблицы в компонентах.
Нам нужно визуализировать данные пользователей в табличной форме с помощью HTML-элемента table. Нужно визуализировать следующий код в React:
<table> <tr> <th>Name</th> <th>Occupation</th> <th>Age</th> </tr> <tr> <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> </tr> <tr> <td>Row Ekemezie</td> <td>Software Dev</td> <td>? :)</td> </tr> </table>
Создадим компоненты для визуализации каждого аспекта элемента table. HeaderComponent отобразит заголовок таблицы, BodyComponent — тело таблицы. TableComponent визуализирует каркас таблицы с HeaderComponent и BodyComponent таким образом:
class TableComponent extends React.Component { render() { return ( <table> <tr> <HeaderComponent /> </tr> <tr> <BodyComponent /> </tr> </table> ) } }
HeaderComponent должен выглядеть так:
class HeaderComponent extends React.Component { render() { return ( <th>Name</th> <th>Occupation</th> <th>Age</th> ) } }
А BodyComponent выглядит вот так:
class BodyComponent extends React.Component { render() { return ( <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> ) } }
Проблема с HeaderComponent и BodyComponent заключается в том, что они выполняют возврат нескольких узлов. React предупредит о необходимости вложить разметку во вложенный тег.
Затем выполняем подобные действия, чтобы устранить предупреждение:
class HeaderComponent extends React.Component { render() { return ( <div> <th>Name</th> <th>Occupation</th> <th>Age</th> </div> ) } } class BodyComponent extends React.Component { render() { return ( <div> <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> </div> ) } }
Разметка вложена в тег div. Теперь на выходе компонент Table будет выглядеть так:
<table> <tr> <div> <th>Name</th> <th>Occupation</th> <th>Age</th> </div> </tr> <tr> <div> <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> </div> </tr> </table>
Выше приведен неправильный вывод элемента table. Элемент div не должен быть отображен. Компоненты React предназначены для возврата элементов, но они должны быть заключены в родительский тег, несколько элементов не могут быть возвращены. Однако добавление дополнительного узла иногда приводит к неправильному форматированию html-элемента output, как показано выше.
Как решить эту проблему? Каким образом можно возвратить заключенные элементы JSX, не влияя на визуализированный вывод в DOM?
Фрагменты React способны решить эту проблему!
Решение — Фрагменты
С помощью фрагментов можно сгруппировать список дочерних элементов без добавления дополнительных узлов в DOM.
Используя <React.Fragment>…</React.Fragment>, можно добавить родительский тег к элементам JSX без добавления дополнительного узла к DOM. React.Fragment не выводит HTMLElement.
Приступим к решению первой проблемы:
class ParentC extends React.Component { render() { return ( <ChildC /> <ChildC /> ) } } class ChildC extends React.Component { render() { return ( <h1> Child Component </h1> ) } }
Теперь выполним вложение:
return ( <ChildC /> <ChildC /> )
в React.Fragment. Получаем такой результат:
class ParentC extends React.Component { render() { return ( <React.Fragment> <ChildC /> <ChildC /> </React.Fragment> ) } }
Перейдем ко второму примеру:
class ParentC extends React.Component { render() { return ( <div> <ChildComponent /> <ChildComponent /> </div> ) } } class ChildComponent extends React.Component { render() { return ( <div> <h1>Hello Child Component</h1> <h1>Hello Child Component</h1> </div> ) } }
Удаляем теги div и добавляем React.Fragment вместо них:
class ParentC extends React.Component { render() { return ( <React.Fragment> <ChildComponent /> <ChildComponent /> </React.Fragment> ) } } class ChildComponent extends React.Component { render() { return ( <React.Fragment> <h1>Hello Child Component</h1> <h1>Hello Child Component</h1> </React.Fragment> ) } }
Переходим к третьему примеру и заменяем дополнительные теги div в BodyComponent и HeaderComponent на React.Fragment:
class HeaderComponent extends React.Component { render() { return ( <div> <th>Name</th> <th>Occupation</th> <th>Age</th> </div> ) } } class BodyComponent extends React.Component { render() { return ( <div> <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> </div> ) } } | | | v class HeaderComponent extends React.Component { render() { return ( <React.Fragment> <th>Name</th> <th>Occupation</th> <th>Age</th> </React.Fragment> ) } } class BodyComponent extends React.Component { render() { return ( <React.Fragment> <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> </React.Fragment> ) } }
Таблица будет отображена следующим образом:
<table> <tr> <th>Name</th> <th>Occupation</th> <th>Age</th> </tr> <tr> <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> </tr> </table>
Как мы и хотели, без лишних тегов div!!!
Если вам кажется, что многократное написание React.Fragmentзанимает слишком много времени, то можно использовать сокращенный синтаксис. Он выглядит таким образом: <>…</>. Теперь компоненты BodyComponent и HeaderComponent выглядят так:
class HeaderComponent extends React.Component { render() { return ( <React.Fragment> <th>Name</th> <th>Occupation</th> <th>Age</th> </React.Fragment> ) } } class BodyComponent extends React.Component { render() { return ( <React.Fragment> <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> </React.Fragment> ) } }
Можно записать и таким образом:
class HeaderComponent extends React.Component { render() { return ( <> <th>Name</th> <th>Occupation</th> <th>Age</th> </> ) } } class BodyComponent extends React.Component { render() { return ( <> <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> </> ) } }
Заключение
Мы рассмотрели проблему невозможности возврата нескольких элементов и способ ее решения с помощью React.Fragment, а также научились использовать сокращенный синтаксис React.Fragment.
Благодаря React.Fragment можно насладиться преимуществом возврата нескольких элементов без необходимости добавлять дополнительные теги или теги div, которые окружают элементы и загромождают DOM.
Специально для сайта ITWORLD.UZ. Новость взята с сайта NOP::Nuances of programming