# Состояние

### Единое дерево состояния

<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/cWw3Zhb" target="_blank" rel="noopener noreferrer">Пройдите этот урок на Scrimba</a></div>

Vuex использует **единое дерево состояния** — когда один объект содержит всё глобальное состояние приложения и служит «единственным источником истины». Это также означает, что в приложении будет только одно такое хранилище. Единое дерево состояния позволяет легко найти нужную его часть или делать снимки текущего состояния приложения в целях отладки.

Единое дерево состояния не противоречит модульности — в следующих главах мы изучим, как можно разделить состояние и мутации на под-модули.

Данные, которые хранятся во Vuex должны следовать тем же правилам, что и `data` в экземпляре Vue, т.е. объект состояния должен быть простым. **См. также:** [Vue#data](https://ru.vuejs.org/v2/api/#data).

### Использование состояния Vuex в компонентах Vue

Итак, как использовать состояние хранилища в компонентах Vue? Поскольку хранилище Vuex реактивно, самый простой способ «получения» — просто вернуть часть состояния хранилища в [вычисляемом свойстве](https://ru.vuejs.org/v2/guide/computed.html):

```js
// создадим компонент-счётчик:
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count() {
      return store.state.count;
    }
  }
};
```

Любые изменения `store.state.count` вызовут перерасчёт вычисляемого свойства и запуск связанных с ним обновлений DOM.

Однако этот паттерн заставляет компонент полагаться на синглтон глобального хранилища. При использовании модульной системы, это потребует импортировать хранилище в каждом компоненте, который использует его состояние, а также усложнит тестирование компонента.

Vuex предоставляет механизм «внедрения» хранилища во всех дочерних компонентах корневого компонента, у которого указана опция `store` (включается в `Vue.use(Vuex)`):

```js
const app = new Vue({
  el: '#app',
  // указываем хранилище в опции «store», что обеспечит
  // доступ к нему также и во всех дочерних компонентах
  store,
  components: { Counter },
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `
});
```

Указывая опцию `store` в корневом экземпляре, мы обеспечиваем доступ к хранилищу во всех дочерних компонентах через `this.$store`. Давайте обновим реализацию `Counter`:

```js
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count() {
      return this.$store.state.count;
    }
  }
};
```

### Вспомогательная функция `mapState`

<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/c8Pz7BSK" target="_blank" rel="noopener noreferrer">Пройдите этот урок на Scrimba</a></div>

Когда компонент должен использовать множество свойств или геттеров хранилища, объявлять все эти вычисляемые свойства может быть утомительно. В таких случаях можно использовать функцию `mapState`, которая автоматически генерирует вычисляемые свойства:

```js
// В полной сборке функция доступна через Vuex.mapState
import { mapState } from 'vuex';

export default {
  // ...
  computed: mapState({
    // стрелочные функции могут сделать код очень кратким
    count: state => state.count,

    // передача строки 'count' аналогична записи `state => state.count`
    countAlias: 'count',

    // для доступа к локальному состоянию через `this`,
    // необходимо использовать обычную функцию
    countPlusLocalState(state) {
      return state.count + this.localCount;
    }
  })
};
```

Можно передавать массив строк в `mapState`, когда имя сопоставляемого вычисляемого свойства совпадает с именем в дереве состояний:

```js
computed: mapState([
  // проксирует в this.count доступ к store.state.count
  'count'
]);
```

### Оператор распространения объектов

Обратите внимание, `mapState` возвращает объект. Как же его использовать в сочетании с другими локальными вычисляемыми свойствами? Для этого обычно приходилось использовать вспомогательные утилиты для объединения нескольких объектов в один, который передавать в `computed`. Однако, с помощью [оператора распространения объектов](https://github.com/tc39/proposal-object-rest-spread) можно значительно упростить синтаксис:

```js
computed: {
  localComputed () { /* ... */ },
  // смешиваем результат mapState с внешним объектом
  ...mapState({
    // ...
  })
}
```

### Компоненты всё ещё могут иметь локальное состояние

Использование Vuex **не означает, что нужно выносить всё состояние** в хранилище. Хотя перемещение большей части состояния во Vuex, сделает мутации более явными и удобными для отладки, это также может привести к многословности и ненужному усложнению логики. Если часть состояния относится только к одному компоненту, лучше оставить его в качестве локального состояния. Вы должны взвесить все компромиссы и принять решение, соответствующее потребностям приложения и вектора его развития.
