# Основы Redux (теория)

_ОБНОВЛЕНИЕ 2018: Вышло_ [_второе издание_](https://maxfarseer.gitbooks.io/redux-course-ru-v2/content/) _(современный код и версии пакетов, данное издание УСТАРЕЛО)_

_На_ [_канале_](http://bit.ly/2IqH74P) _так же проводятся бесплатные вебинары, публикуются переводы и авторские материалы,_ [_присоединяйтесь_](http://bit.ly/2IqH74P)_!_

## Основы Redux (теория)

Курс рассчитан на создание приложения по шагам, а это значит максимум практики и минимум теории. Тот самый минимум, перед вами.

Давайте еще раз взглянем на схему нашего приложения: ![приложение](https://721505618-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LvLmy8wH1HhL0UsjoVp%2F-LvLmyaitqCV1tR5_kQb%2F-LvLnLoGgO3k3DmqCXCc%2Fsample_app.jpg?generation=1575561827505151\&alt=media)

В шапке слева заголовок и три кнопки выбора года. Ниже - фото соответствующего года, отсортированное по количеству лайков.

В шапке справа - ссылка войти/выйти.

Представим, как должны выглядеть данные для такой страницы:

```javascript
app: {
    page: {
        year: 2016,
        photos: [photo, photo, photo...]
    },
    user: {
        name: 'Имя',
        ...
    }
}
```

Поздравляю вас, мы только что описали как должно выглядеть состояние (**state**) нашего приложения.

За содержание всего состояния нашего приложения, отвечает объект **Store**. Как уже не раз упоминалось - это обычный объект. Важно, что в отличии от Flux, в Redux только **один** объект Store.

Не хочется оставлять вас надолго без практики, поэтому процесс создания store и немного подробностей про него я аккуратно вплету в следующие главы, а пока достаточно того, что: _store_, "объединяет" редьюсер (_reducer_) и действия (_actions_), а так же имеет несколько чрезвычайно полезных методов, например:

* `getState()` - позволяет получить состояние приложения;
* `dispatch(actions)` - позволяет обновлять состояния, путем вызова действия;
* `subcribe(listener)` - регистрирует слушателей

### Actions

Actions описывают действия.

Actions - это простой объект. Обязательное поле - **type**. Так же, если следовать [соглашению](https://github.com/acdlite/flux-standard-action), все данные, которые передаются вместе с действием, кладут внутрь свойства payload. Таким образом, для нашего приложения, мы можем составить, например такую пару actions:

```javascript
{
    type: 'ЗАГРУЗИ_ФОТО',
    payload: 2016 //год
}
```

```javascript
{
    type: 'ФОТО_ЗАГРУЖЕНЫ_УСПЕШНО',
    payload: [массив фото]
}
```

Чтобы вызвать actions, мы должны написать функцию, которая в рамках Flux/Redux называется - _ActionsCreator_ (создатель действия), но перед этим стоит принять во внимание, что обычно тип действия, описывают как константу. Например, константы вашего проекта:

```javascript
const GET_PHOTO_REQUEST = 'GET_PHOTO_REQUEST'
const GET_PHOTO_SUCCESS = 'GET_PHOTO_SUCCESS'
```

Возникает вопрос, зачем? В маленьких проектах - незачем. В больших - это удобно. Пока, _просто запомните_.

Вернемся, к ActionsCreator, один из наших "создателей действий", выглядел бы так:

```javascript
function getPhotos(year) {
  return {
    type: GET_PHOTOS,
    payload: year
  }
}
```

**Итого**: actions сообщает нашему приложению - "Эй, что-то произошло! И я знаю, что именно!"

### Reducer

_"Actions описывает факт, что что-то произошло, но не указывает, как состояние приложения должно измениться в ответ, это работа для Reducer'а"_ - ([офф. документация](http://redux.js.org/docs/basics/Reducers.html))

Наше приложение не нуждается в нескольких редьюсерах, но крайне необходимо познакомить читателя с **reducer composition**, так как это фундаментальный шаблон построения redux приложений: **мы разбиваем наше глобальное состояние на кусочки, за каждый кусочек отвечает свой reducer**. Кусочки объединяются в Корневом Редьюсере (rootReducer).

Схематично, наше приложение можно представить так: ![приложение\_редьюсер](https://721505618-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LvLmy8wH1HhL0UsjoVp%2F-LvLmyaitqCV1tR5_kQb%2F-LvLnLoLHrEYTePPclXw%2Fsample_app_reducer.jpg?generation=1575561848116973\&alt=media)

Так как у нас есть reducer'ы `page` и `user`, можно представить следующий диалог:

```
pageActions: Пришло 123 фото
Reducer (page): Ок, нужно положить эти 123 фото в page.photos
```

А на js выглядело бы так:

```javascript
function page(state = initialState, action) {
  switch (action.type) {
    case GET_PHOTO_SUCCESS:
      return Object.assign({}, state, {
        photos: action.payload
      })
    default:
      return state
  }
}
```

Обратите внимание, мы не **мутировали** наш state, мы создали новый state. Это важно. Крайне важно. В редьюсере, мы всегда должны возвращать новый объект, а не измененный предыдущий.

На практике, я буду использовать [object spread syntax](https://github.com/sebmarkbage/ecmascript-rest-spread), поэтому предыдущую функцию с Object.assign можно переписать следующим образом:

```javascript
function page(state = initialState, action) {
  switch (action.type) {
    case GET_PHOTO_SUCCESS:
      return {...state, photos: action.payload} //Object spread syntax
    default:
      return state
  }
}
```

Объект, который мы возвращаем в редьюсере, далее с помощью функции `connect`, превратится в свойства для компонентов. Таким образом, если продолжить пример с фото, то можно написать такой псевдо-код:

```javascript
<Page photos={reducerPage.photos} />
```

Благодаря этому, внутри компонента `<Page />`, мы сможем получить фото, как `this.props.photo`

Я постарался очень кратко дать самую важную теорию.

Если что-то осталось не понятным, не переживайте, на практике мы все закрепим и тогда все встанет на свои места.
