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

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) на данный момент.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://max-frontend.gitbook.io/react-course-ru-v2/sozdanie-komponenta.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
