Книга: react-course-ru-v2
Назад: Подключаем react как script
Дальше: Использование props

Создание компонента

Создание компонента

ReactDOM.render принимает react-компонент (далее буду называть просто "компонент") и DOM-элемент, в который мы хотим "примонтировать" наше приложение.

<h1>Hello, world!</h1> - как ни странно, это примитивный компонент.

Пока ничего интересного, но давайте представим такой псевдо-код:

var photos = ['images/cat.jpg','images/dog.jpg','images/owl.jpg']  ReactDOM.render(   <App>     <Photos photos=photos />     <LastNews />     <Comments />   </App>,   document.getElementById('root') ); 

Что примечательного в данном псевдо-коде? Он очень хорошо читается, ведь очевидно, что наше приложение (App) отображает: фото (кошка, собака, сова), новости и комментарии.

Хочу вас обрадовать, React.js код выглядит практически так же. Он отлично читается, так как деление на компоненты позволяет отлично структурировать код.

Давайте создадим примитивный компонент:

index.html

<!DOCTYPE html> ...   <body>     <div id="root"></div>     <script type="text/babel">        const App = () => {         return <p>Всем привет, я компонент App</p>       }              ReactDOM.render(         <App />,         document.getElementById('root')       );      </script>    </body> </html> 

Что примечательного? Мы скрыли в <App /> разметку. Да, в этом примере это одна строка и чувство эйфории отсутствует, но то ли еще будет! Пока запомним, что если мы хотим отрисовать в JSX компонент, то мы обязательно должны называть и вызывать его с Большой буквы.

Смотрим на результирующий html-код:


Мы создали компонент с помощью функции. Но компоненты, можно создавать и с помощью class. Убьем сразу нескольких зайцев:

  • изучим как создавать компоненты с помощью class
  • как передать css-стиль
  • как отрисовать сразу несколько компонентов

index.html

<!DOCTYPE html> <html>   <head>     <meta charset="UTF-8" />     <title>React [RU] Tutorial v2</title>     <script src="https://unpkg.com/react@16/umd/react.development.js"></script>     <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>     <script src="https://unpkg.com/[email protected]/babel.min.js"></script>      <style>       .red {         color: #FF0000;       }     </style>   </head>   <body>     <div id="root"></div>     <script type="text/babel">        const App = () => {         return <p>Всем привет, я компонент App</p>       }        class BigApp extends React.Component {         render() {           return (             <div>               <h1>Я компонент, BigApp</h1>               <p className='red'>Компоненты можно вкладывать друг в друга.</p>               <App/>             </div>           )         }       }        ReactDOM.render(         <BigApp />,         document.getElementById('root')       );      </script>    </body> </html> 

Синтаксис:

class (название) extends (что будем наследовать) 

так же позволяет создать компонент. Здесь стоит отметить, что если компонент создан с помощью класса, то JSX разметка пишется внутри метода render. Это ключевой метод, в котором мы указываем, что будет отображаться пользователю на странице.

Компоненты созданные с помощью class, называются statefull компоненты (то есть, компоненты с состоянием), а компоненты созданные с помощью функции - stateless component (то есть, компоненты без состояния). Зачем такое деление - узнаем позже.

В примере мы добавили стиль для параграфа, через className, а не через class, как мы привыкли делать это. Почему? Потому что, мы находимся внутри JSX-синтаксиса, в котором html и js идут вперемешку, а слово class зарезервировано в javascript.

Напоследок отмечу, что мы с легкостью смогли вложить один компонент в другой.

В разметке все как мы и ожидали. Однако, я уже вижу читателей, кому не нравится лишний div.


Каждый компонент должен возвращать один узел

Рассмотрим проблему с div'ом. Как написано в заголовке, мы должны возвращать всегда один dom-узел. Попробуем удалить div:

index.html

<script type="text/babel">    const App = () => {     return <p>Всем привет, я компонент App</p>   }    class BigApp extends React.Component {     render() {       // убрали div       return (         <h1>Я компонент, BigApp</h1>         <p className='red'>Компоненты можно вкладывать друг в друга.</p>         <App/>       )     }   }    ReactDOM.render(     <BigApp />,     document.getElementById('root')   );  </script> 

Ошибка: jsx-элементы должны быть обернуты в один тэг. Что делать, если не хочется городить еще один div? Ответ: React.Fragment

Все довольны. Разницы особо нет, как вам больше нравится, так и пишите, но помните: все что вы возвращаете в render методе или в return у stateless-компонента должно быть обернуто в один тэг / React.Fragment.


Давайте разовьем идею: научим BigApp отображать новости. Для этого, нам потребуется создать компонент <News /> и вложить его в BigApp.

index.html

const App = () => {   return <p>Всем привет, я компонент App</p> }  const News = () => {   return <p>К сожалению, новостей нет</p> }  class BigApp extends React.Component {   render() {     return (       <React.Fragment>         <h1>Я компонент, BigApp</h1>         <p className='red'>Компоненты можно вкладывать друг в друга.</p>         <App />         <News />       </React.Fragment>     )   } }  ReactDOM.render(   <BigApp />,   document.getElementById('root') ); 

Давайте, вновь взглянем на код и поищем примечательные места.

Во-первых - мы никак не изменили код внутри ReactDOM.render. Мы просто вложили в BigApp еще один компонент.

Во-вторых, как уже было сказано - компонент <BigApp /> содержит в себе компонент <News />, словно это просто дочерний <div></div> элемент.

В-третьих, наш компонент <News /> такой же примитивный, как и App, поэтому мы создали его через функцию (а не через class).


Задачка на понимание происходящего: Удалите компонет <BigApp/>, оставьте <App /> (не переписывая его на statefull-компонент). В <App /> отображайте <News />. Так же создайте компонент <Comments /> и сделайте, чтобы он отображался после новостей. Текст компонента: "Нет новостей - комментировать нечего."

Решение для задачи всегда публикуется ниже по тексту, и обычно содержит сначала подсказки, а потом код всего решения. Здесь подсказок нет.

Решение:

index.html

<!DOCTYPE html> <html>   <head>     <meta charset="UTF-8" />     <title>React [RU] Tutorial v2</title>     <script src="https://unpkg.com/react@16/umd/react.development.js"></script>     <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>     <script src="https://unpkg.com/[email protected]/babel.min.js"></script>      <style>       .red {         color: #FF0000;       }     </style>   </head>   <body>     <div id="root"></div>     <script type="text/babel">        const News = () => {         return <p>К сожалению, новостей нет</p>       }        const Comments = () => {         return <p>Нет новостей - комментировать нечего.</p>       }        const App = () => {         return (           <React.Fragment>             <News />             <Comments />           </React.Fragment>         )       }        ReactDOM.render(         <App />,         document.getElementById('root')       );      </script>    </body> </html> 

Прежде чем переходить к следующему уроку, предлагаю вам установить react devtools (плагин для , плагин для ).

Так как мы разрабатываем просто в файлике index.html, нужно активировать опцию в плагине (в хроме выглядит так):

После установки и настройки откройте вкладку React в консоли разработчика.

Пытливый читатель уже заметил окошечко "Props". Ок, об этом и поговорим в следующей главе.

на данный момент.

Назад: Подключаем react как script
Дальше: Использование props