Публикуем очередную часть перевода учебного курса по React. Нашей сегодняшней темой будут взаимоотношения родительских и дочерних компонентов.
→ Часть 1: обзор курса, причины популярности React, ReactDOM и JSX
→ Часть 2: функциональные компоненты
→ Часть 3: файлы компонентов, структура проектовЗанятие 9. Родительские и дочерние компоненты
Сегодня мы поговорим о родительских и дочерних компонентах. Использование подобных конструкций сделает наше приложение гораздо более сложным, чем в случае, когда в нём был всего один компонент, выводимый в DOM, такой, как
MyInfo. Вместо этой простой структуры в приложении может присутствовать сложная иерархия компонентов, которая, в итоге, преобразуется в JSX-элементы.
Начнём с уже знакомого вам шаблона приложения. Для того чтобы вспомнить пройденное, можете, по памяти, в пустом файлеindex.js, написать код для вывода на страницу заголовка первого уровня с текстомHello World!средствами React. Вот как может выглядеть подобный код:import React from "react"import ReactDOM from "react-dom"ReactDOM.render(<h1>Hello World!</h1>,document.getElementById("root"))В прошлый раз там, где в вышеприведённом коде находится описание элемента
<h1>, присутствовал код для вывода компонентаMyInfo. Теперь же мы собираемся создать компонентAppи вывести его. Для этого нам понадобится код следующего вида:import React from "react"import ReactDOM from "react-dom"ReactDOM.render(<App />,document.getElementById("root"))Компонент
Appбудет точкой входа в наше приложение. Вероятно, вы уже заметили, что в коде предыдущего примера кое-чего не хватает. Это действительно так — мы пока не импортировали сюдаApp. Сделаем это:import React from "react"import ReactDOM from "react-dom"import App from "./App"ReactDOM.render(<App />,document.getElementById("root"))Но такой код всё ещё остаётся нерабочим. Нам нужен файл компонента
App(App.js), расположенный в той же папке, что иindex.js. Именно к такому файлу мы обращаемся в команде импортаimport App from "./App". Напомним, что имена компонентов React записываются в верблюжьем стиле и начинаются с заглавной буквы. Создадим нужный нам файл и опишем в нём компонентApp. Попытайтесь сделать это самостоятельно. А именно — напишите код, благодаря которому компонентAppвыведет на страницу текстHello again.
Вот как выглядит этот код:import React from "react"function App(){return (<h1>Hello again</h1>)}export default AppТут функция
Appвозвращает единственный элемент, но напомним, что из подобных функций можно возвращать и более сложные структуры. Самое главное — не забывать о том, что возвратить можно лишь один элемент, который, если, на самом деле, вывести нужно несколько элементов, представляет собой контейнер, включающий их в себя. Например, вот как будет выглядеть возврат разметки, описывающей заголовок первого уровня и маркированный список:import React from "react"function App(){return (<div><h1>Hello a third time!</h1><ul><li>Thing 1</li><li>Thing 2</li><li>Thing 3</li></ul></div>)}export default AppВозможно, сейчас мы решим, что то, что формируется средствами компонента
App, должно представлять собой некий веб-сайт. У него будет навигационный блок (<nav></nav>) и область основного содержимого (<main></main>). Это решение приведёт к формированию следующего кода:import React from "react"function App(){return (<div><nav><h1>Hello a third time!</h1><ul><li>Thing 1</li><li>Thing 2</li><li>Thing 3</li></ul></nav><main><p>This is where most of my content will go...</p></main></div>)}export default AppВот как всё это будет выглядеть в браузере.
Приложение в браузере
Тут ещё можно стилизовать список для того, чтобы он стал больше похожим на навигационную панель.
Можно заметить, что код компонента уже стал довольно большим. Это идёт вразрез с целью, ради которой мы используем React. Ранее мы говорили о том, что фрагменты HTML-кода можно представлять в виде отдельных компонентов, а в нашем компоненте всё свалено в одну кучу. Поэтому сейчас мы создадим компоненты для каждого самостоятельного фрагмента разметки.
Взгляните на эту схему для того, чтобы лучше разобраться в том, о чём идёт речь.
Компонент App выводит компонент MyInfo, выводящий элемент <div>
Тут мы выводим на страницу компонент
App. При этом компонентAppрешает вывести ещё один компонент —MyInfo. А уже компонентMyInfoвыводит некий JSX-элемент. Обратите внимание на разницу между понятиями «компонент» и «элемент». Элементы — это сущности, которые превращаются в обычный HTML-код. Так, в элементе, представленном в нижней части схемы, используется простой тег<div>, его имя начинается с маленькой буквы, что говорит нам о том, что это — обычный элемент, а не один из созданных нами компонентов. С другой стороны, имяMyInfoначинается с большой буквы. Это помогает понять, что перед нами — компонент.
Вы могли слышать о том, что DOM (Document Object Model, объектная модель документа) часто называют «деревом». Корневым элементом этого дерева является элемент<html>. В нашем случаем корневым элементом дерева, представленного на схеме, является компонентApp. Возможности этого компонента не ограничиваются выводом другого компонента,MyInfoв нашем случае. Он может, например, вывести ещё один компонент, представляющий собой «подвал», нижнюю часть страницы. Скажем, этот компонент будет носить имяAwesomeFooter.
Компонент App выводит два компонента
Этот компонент, в свою очередь, может вывести элемент
<footer>, который будет содержать HTML-код нижней части страницы.
Если у нас имеется «подвал» страницы, то она может содержать и «шапку», оформляющую её верхнюю часть.
Компонент App выводит три компонента
Верхняя часть страницы представлена на нашей схеме компонентом
AwesomeHeader. Такие имена этим компонентам даны для того, чтобы не путать их с элементами. КомпонентAwesomeHeader, как и компонентApp, может выводить не только JSX-разметку, но и другие компоненты. Например, это может быть компонентNavBar, представляющий собой навигационную панель, и компонентLogo, выводящий логотип. А эти компоненты уже выведут обычные элементы — такие, как<img />и<nav>.
По мере рассмотрения этой схемы вы можете заметить, что React-приложение, в ходе его развития, может становиться всё более и более сложным. И то, что мы тут рассмотрели, на самом деле, представляет собой пример крайне простой структуры приложения.
Теперь давайте создадим в нашем учебном приложении компонент, который будет представлять собой «подвал» страницы.
Для этого создадим, в той же папке, где находится файлindex.js, новый файл. Назовём егоFooter.jsи поместим в него следующий код:import React from "react"function Footer() {return (<footer><h3><font color="#3AC1EF">▍This is my footer element</font></h3></footer>)}export default FooterОбратите внимание на то, что имя функционального компонента начинается с большой буквы (
Footer), а имя элемента(<footer>) — с маленькой. Как уже было сказано, это помогает отличать элементы от компонентов.
Если теперь обновить страницу, то разметка, формируемая компонентомFooter, в её нижней части выведена не будет. Это совершенно ожидаемо, так как для того, чтобы её вывести, нужно внести соответствующие изменения в код компонентаApp.
А именно, речь идёт о том, что в коде файла компонентаAppнужно импортировать компонентFooterи создать его экземпляр. Отредактируем код файлаApp.js:import React from "react"import Footer from "./Footer"function App(){return (<div><nav><h1>Hello a third time!</h1><ul><li>Thing 1</li><li>Thing 2</li><li>Thing 3</li></ul></nav><main><p>This is where most of my content will go...</p></main><Footer /></div>)}export default AppТеперь страница, которую формирует приложение, будет выглядеть так, как показано ниже.
Компонент App выводит в нижней части страницы разметку, формируемую другим компонентом — Footer
Можно заметить, что сейчас в коде, выводимом компонентом
App, имеется странная смесь из обычных JSX-элементов с компонентами. Куда лучше было бы, если бы то, что выводит компонентApp, было бы похоже на нечто вроде оглавления книги, чтобы в нём присутствовали, в основном, компоненты. А именно, речь идёт о том, чтобы код компонента выглядел бы примерно так:import React from "react"import Footer from "./Footer"function App() {return (<div><Header /><MainContent /><Footer /></div>)}export default AppЕсли приложение имеет подобную структуру (в нашем случае, так как файлы компонентов
HeaderиMainContentпока не созданы, код работать не будет), то описание элементов, формирующих различные части страницы, будет находиться в файлах соответствующих компонентов. При этом компоненты, импортируемые в компонентApp, могут содержать другие вложенные компоненты. Так могут быть сформированы довольно обширные структуры, размеры которых определяются нуждами конкретного приложения.
Здесь мы поговорили о том, как работать с вложенными компонентами. Вы вполне можете попробовать на практике то, что только что узнали, приведя проект, файлApp.jsкоторого выглядит так, как показано выше, в рабочее состояние.Занятие 10. Практикум. Родительские и дочерние компоненты
▍Задание
Создайте React-приложение с нуля. Выведите на страницу корневой компонент
App(определённый в отдельном файле). Внутри этого компонента выведите следующие компоненты:
Navbar
MainContent
FooterКомпоненты, выводимые
App, должны быть описаны в отдельных файлах, каждый из них должен выводить какие-нибудь JSX-элементы.▍Решение
В качестве основы для решения этой задачи используется стандартный проект, создаваемый средствами
create-react-app.
Код файлаindex.js:import React from "react"import ReactDOM from "react-dom"import App from "./App"ReactDOM.render(<App />,document.getElementById("root"))Вот код файла
App.js. Обратите внимание на то, что для хранения файлов компонентов мы будем использовать папкуcomponents.import React from "react"import Header from "./components/Header"import MainContent from "./components/MainContent"import Footer from "./components/Footer"function App() {return (<div><Header /><MainContent /><Footer /></div>)}export default AppКод файла
Header.js:import React from "react"function Header() {return (<header>This is the header</header>)}export default HeaderКод файла
MainContent.js:import React from "react"function MainContent() {return (<main>This is the main section</main>)}export default MainContentКод файла
Footer.js:import React from "react"function Footer() {return (<footer>This is the footer</footer>)}export default FooterРаботу с компонентами вы можете организовать так, как вам будет удобнее. То есть, можно, например, сначала написать в файле
App.jsвесь необходимый код, выполняющий импорт компонентов и вывод их экземпляров, а потом создать файлы компонентов. Можно сделать всё наоборот — сначала создать файлы компонентов с кодом, а потом уже работать над файломApp.js. Самое главное, чтобы в итоге получилось работающее приложение.
Вот как выглядит проект в VSCode.
Проект в VSCode
А вот как выглядит страница, которую сформировало это приложение.
Страница приложения в браузере
Наше React-приложение работает, но то, что оно выводит на страницу, выглядит как-то совсем неинтересно. Исправить это можно, стилизовав содержимое страницы.
Итоги
Сегодня мы поговорили о родительских и дочерних компонентах. В следующий раз мы начнём работу над нашим первым большим учебным проектом и поговорим о стилизации элементов страницы.
JavaScript







