> For the complete documentation index, see [llms.txt](https://max-frontend.gitbook.io/react-course-ru-v2/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://max-frontend.gitbook.io/react-course-ru-v2/sozdanie-komponenta.md).

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

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

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

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

```jsx
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*

```jsx
<!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-код:

![](/files/-LvLnVGnbWtX0BCjWVVD)

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

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

*index.html*

```jsx
<!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/babel-standalone@6.15.0/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.

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

![](/files/-LvLnVH20dw7EJoDaEQp)

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

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

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

*index.html*

```jsx
<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>
```

![](/files/-LvLnVH5lQC2AQpLQ4dQ)

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

![](/files/-LvLnVH72WFa7Z_HxYeI)

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

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

*index.html*

```jsx
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 />` и сделайте, чтобы он отображался после новостей. Текст компонента: "Нет новостей - комментировать нечего."

![](/files/-LvLnVH9zU6qWpxxTQN_)

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

**Решение**:

*index.html*

```jsx
<!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/babel-standalone@6.15.0/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 (плагин для [хрома](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi), плагин для [мозилы](https://addons.mozilla.org/en-us/firefox/addon/react-devtools/)).

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

![](/files/-LvLnVHG2Q83eOOeIwOs)

![](/files/-LvLnVHI2wB1orO-zA3x)

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

![](/files/-LvLnVHKr2Gk-mnDbb0N)

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

[Исходный код](https://github.com/maxfarseer/react-course-ru-v2/tree/chp2-create-components) на данный момент.
