# Использование state

Вернемся от теории к практике: давайте покликаем по ссылкам-кнопочкам, поизменяем свойства компонентов...

Упс, не выйдет! Как вы помните, свойства (*this.props*) следует использовать только для чтения, а для динамических свойств нужно использовать так называемое "состояние" (*state*).

Итак, встречайте - **this.state** ;)

Так как мне нужно в этом разделе сохранить минимум теории и больше практики, сразу перейдем к делу. Предлагаю вместе решить следующую задачу: *у новости есть ссылка "подробнее", по клику на которую - бинго, текст новости целиком*.

Начнем с изменения данных:

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

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

```javascript
class Article extends React.Component {
  render() {
    const { author, text, bigText } = this.props.data // вытащили bigText из даты
    return (
      <div className='article'>
        <p className='news__author'>{author}:</p>
        <p className='news__text'>{text}</p>
        <p className='news__big-text'>{bigText}</p>
      </div>
    )
  }
}

Article.propTypes = {
  data: PropTypes.shape({
    author: PropTypes.string.isRequired,
    text: PropTypes.string.isRequired,
    bigText: PropTypes.string.isRequired // добавили propTypes для bigText
  })
}
```

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

Проверим...

![news with readmore](/files/-LvLnSprHuVObJEeaLNE)

Отлично, можно продолжать работу: добавим ссылку - "подробнее". Приведу фрагмент кода:

```javascript
...
return (
  <div className='article'>
    <p className='news__author'>{author}:</p>
    <p className='news__text'>{text}</p>
    <a href="#" className='news__readmore'>Подробнее</a>
    <p className='news__big-text'>{bigText}</p>
  </div>
)
...
```

Проверьте и если все ок - мы готовы к работе с состоянием компонента.

## Начальное состояние

*С состоянием (state) можно работать только в statefull компонентах (class)*

Если вы определяете какое-то изменяемое свойство в компоненте, необходимо указать начальное состояние (в терминологии react.js - *initial state*). Для этого, у компонента нужно просто определить свойство state:

```javascript
class Article extends React.Component {
  state = {
    visible: false, // определили начальное состояние
  }
  render() {
    const { author, text, bigText } = this.props.data
    return (
      <div className='article'>
        <p className='news__author'>{author}:</p>
        <p className='news__text'>{text}</p>
        <a href="#" className='news__readmore'>Подробнее</a>
        <p className='news__big-text'>{bigText}</p>
      </div>
    )
  }
}
```

Посмотрим в консоли на вкладке React:

![news initial state](/files/-LvLnSptR_NSZO-a2EDL)

В состоянии (*в state*) появилось свойство. Будем использовать его в момент render'а.

Формализуем задачу:

* если значение this.state.visible === false -> рисуй "подробнее", не рисуй "большой текст";
* если же this.state.visible === true -> не рисуй "подробнее", рисуй большой текст;

Будем использовать логическое выражение внутри JSX, значит - фигурные скобки, и внутри js-выражение.

```javascript
class Article extends React.Component {
  state = {
    visible: false,
  }
  render() {
    const { author, text, bigText } = this.props.data
    const { visible } = this.state // вытащили visible из this.state
    return (
      <div className='article'>
        <p className='news__author'>{author}:</p>
        <p className='news__text'>{text}</p>
        { /* если не visible, то показывай */
          !visible && <a href="#" className='news__readmore'>Подробнее</a>
        }
        { /* если visible, то показывай */
          visible && <p className='news__big-text'>{bigText}</p>
        }
      </div>
    )
  }
}
```

Мы использовали одну и ту же переменную состояния в **двух** местах когда описывали обычное javascript выражение. Если вы не знакомы с И / ИЛИ, то рекомендую почитать у Кантора ([Логические операторы](https://learn.javascript.ru/logical-ops)).

Обратите внимание, для написания комментариев не понадобились дополнительные фигурные скобки, так как мы уже находились внутри "выражения" внутри JSX.

Можете проверить в браузере, и покликать на чекбокс внутри state зоны. Шаблон уже будет реагировать. А мы продолжим делать все это по-человечески, чтобы можно было кликать на "подробнее".

## Обработка кликов - onClick

Чтобы обработать клик, нам необходимо указать атрибут *onClick* у элемента.

В качестве обработчика у нас будет функция, которая изменяет состояние. Для изменения состояния, нужно **обязательно** использовать метод **setState**, а не перезаписывать значение переменной в this.state напрямую.

```javascript
class Article extends React.Component {
  state = {
    visible: false,
  }
  handleReadMoreClck = (e) => { // добавили метод
    e.preventDefault()
    this.setState({ visible: true })
  }
  render() {
    const { author, text, bigText } = this.props.data
    const { visible } = this.state
    return (
      <div className='article'>
        <p className='news__author'>{author}:</p>
        <p className='news__text'>{text}</p>
        { /* добавили onClick */
          !visible && <a onClick={this.handleReadMoreClck} href="#" className='news__readmore'>Подробнее</a>
        }
        {
          visible && <p className='news__big-text'>{bigText}</p>
        }
      </div>
    )
  }
}
```

Проверьте в браузере, кликните на ссылку "подробнее".

Каждый компонент `<Article />` имеет свое состояние! Поэтому, при клике на подробнее в одном из компонентов, только его состояние изменяется, и только у этой новости отображается полный текст.

![news last readmore](/files/-LvLnSpvKN2FjxaDmPg0)

**Итого**:

Для сохранения динамических свойств, используется состояние (*state*) компонента.

Для обработки клика, используется свойство *onClick* + функция-обработчик. Существуют и другие стандартные события, которые работают по такому же принципу. Полный список [здесь](https://reactjs.org/docs/events.html#supported-events). Мы будем знакомиться с ними по мере необходимости.

Для изменения состояния, используется метод **setState**, который принимает объект с аргументами, которые нужно изменить. Например, у нас есть состояние:

```javascript
...
state = {
  visible: false,
  rating: 0,
  eshe_odno_svoistvo: 'qweqwe'
}
...
```

Чтобы изменить рейтинг, нужно написать следующий setState:

```javascript
this.setState({rating: 100500})
```

Чтобы изменить все три свойства:

```javascript
this.setState({
    rating: 100500,
    visible: true,
    eshe_odno_svoistvo: 'привет'
})
```

Так же у *setState* есть возможность указать *callback* функцию, которая будет вызвана после того, как новое состояние "установится".

```javascript
...
readmoreClick: function(e) {
    e.preventDefault();
    this.setState({ visible: true }, () => {
      alert('Состояние изменилось');
    });
  },
...
```

Еще *setState* есть возможность... (на самом деле есть, но с нас пока хватит).

Посмотреть полный список возможностей setState можно в [документации](https://reactjs.org/docs/react-component.html#setstate).

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


---

# 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/ispolzovanie-state.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.
