# Порефакторим...

Для начала, удалите вовсе компонент `<Comments />` (и `const Comments...` соответственно).

Далее, давайте представим: у наших новостей появляются какие-то дополнительные поля, пользователь начинает взаимодействовать с ними, например "пометить как прочитанное" и так далее. Нам было бы удобно, чтобы каждая новость была представлена отдельным компонентом.

**Задача**: `<News />` должен рендерить список компонентов `<Article />`. Каждый компонент `<Article />` должен получать соответствующие данные, например: первый экземпляр получит первый элемент массива, второй - второй и так далее.

То есть, раньше в map мы возвращали JSX-разметку. Но мы так же можем возвращать и компонент.

Попробуйте сами, а потом смотрите решение ниже.

Подсказка **#1**: if-else нашего компонента `<News />`

```jsx
if (data.length) {
  newsTemplate = data.map(function(item) {
    return <Article key={item.id} data={item}/>
  })
} else {
  newsTemplate = <p>К сожалению новостей нет</p>
}
```

Подсказка **#2** (по сути решение задачи): компонент `<Article />`

```jsx
class Article extends React.Component {
  render() {
    const { author, text } = this.props.data
    return (
      <div className="article">
        <p className="news__author">{author}:</p>
        <p className="news__text">{text}</p>
      </div>
    )
  }
}
```

Что любопытно, больше не изменилось ни-че-го.

![](/files/-LvLnSrCpQLPCXQ9FcCl)

Добавьте заголовок "Новости" в `<App />` перед компонентом `<News />`

```javascript
const App = () => {
  return (
    <React.Fragment>
      <h3>Новости</h3>
      <News data={myNews}/>
    </React.Fragment>
  )
}
```

Добавьте красоты (CSS) по вкусу, либо возьмите мой вариант:

```css
.none {
  display: none;
}

body {
  background: rgba(0, 102, 255, 0.38);
  font-family: sans-serif;
}

p {
  margin: 0 0 5px;
}

.article {
  background: #FFF;
  border: 1px solid rgba(0, 89, 181, 0.82);
  width: 600px;
  margin: 0 0 5px;
  box-shadow: 2px 2px 5px -1px rgb(0, 81, 202);
  padding: 3px 5px;
}

.news__author {
  text-decoration: underline;
  color: #007DDC;
}
.news__count {
  margin: 10px 0 0 0;
  display: block;
}
```

С новыми стилями, код сценария выглядит так:

*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>
      .none {
        display: none;
      }

      body {
        background: rgba(0, 102, 255, 0.38);
        font-family: sans-serif;
      }

      p {
        margin: 0 0 5px;
      }

      .article {
        background: #FFF;
        border: 1px solid rgba(0, 89, 181, 0.82);
        width: 600px;
        margin: 0 0 5px;
        box-shadow: 2px 2px 5px -1px rgb(0, 81, 202);
        padding: 3px 5px;
      }

      .news__author {
        text-decoration: underline;
        color: #007DDC;
      }
      .news__count {
        margin: 10px 0 0 0;
        display: block;
      }
    </style>
  </head>
  <body>
    <div id="root"></div>
    <script type="text/babel">

      const myNews = [
        {
          id: 1, // добавили id
          author: 'Саша Печкин',
          text: 'В четверг, четвертого числа...'
        },
        {
          id: 2,
          author: 'Просто Вася',
          text: 'Считаю, что $ должен стоить 35 рублей!'
        },
        {
          id: 3,
          author: 'Max Frontend',
          text: 'Прошло 2 года с прошлых учебников, а $ так и не стоит 35'
        },
        {
          id: 4,
          author: 'Гость',
          text: 'Бесплатно. Без смс, про реакт, заходи - https://maxpfrontend.ru'
        }
      ];

      class Article extends React.Component {
        render() {
          const { author, text } = this.props.data
          return (
            <div className="article">
              <p className="news__author">{author}:</p>
              <p className="news__text">{text}</p>
            </div>
          )
        }
      }

      class News extends React.Component {
        render() {
          const { data } = this.props
          let newsTemplate

          if (data.length) {
            newsTemplate = data.map(function(item) {
              return <Article key={item.id} data={item}/>
            })
          } else {
            newsTemplate = <p>К сожалению новостей нет</p>
          }

          return (
            <div className="news">
              {newsTemplate}
              {
                data.length ? <strong className={'news__count'}>Всего новостей: {data.length}</strong> : null
              }
            </div>
          );
        }
      }

      const App = () => {
        return (
          <React.Fragment>
            <h3>Новости</h3>
            <News data={myNews}/>
          </React.Fragment>
        )
      }

      ReactDOM.render(
        <App />,
        document.getElementById('root')
      );

    </script>

  </body>
</html>
```

В целом меня устраивает почти все. Осталось немного отполировать метод render компонента `<News />`. Правило следующее: стараемся в render держать как можно меньше кода, чтобы его было легко читать вашим коллегам. Для этого, мы newsTemplate будем заполнять внутри нового метода, который будем вызывать в render.

```jsx
class News extends React.Component {
  renderNews = () => {
    const { data } = this.props
    let newsTemplate = null

    if (data.length) {
      newsTemplate = data.map(function(item) {
        return <Article key={item.id} data={item}/>
      })
    } else {
      newsTemplate = <p>К сожалению новостей нет</p>
    }

    return newsTemplate
  }
  render() {
    const { data } = this.props

    return (
      <div className="news">
        {this.renderNews()}
        {
          data.length ? <strong className={'news__count'}>Всего новостей: {data.length}</strong> : null
        }
      </div>
    );
  }
}
```

Что примечательного в этом коде?

Мы создали метод renderNews (внутри class) с помощью так называемой "жирной стрелочной функции" (запись вида `methodName = () => ...`). При такой записи, внутри функции мы не теряем контекст `this`. То есть, можем обращаться к `this.props`, например.

Почему мы метод `render` не описываем через жирную стрелочную функцию? Потому что, это метод жизненного цикла react-компонента, и туда this "прокидывает" уже сам react.

Далее, так как мы `renderNews` создали в качестве метода, значит внутри компонента, мы должны обращаться к нему как `this.XXX` (где `XXX` - название метода, в нашем случае `renderNews`).

Что же изменилось, спросите вы? Было много кода в render, стало чуть выше. Дело в том, что когда ваши компоненты разрастутся, очень удобно иметь "рендер" хорошо читаемым, то есть таким, в котором все лишнее спрятано.

Посмотрим, что вышло в итоге:

![](/files/-LvLnSrJXcdLqv8EB6TK)

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


---

# 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/porefaktorim.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.
