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

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

Давайте еще раз взглянем на схему нашего приложения: ![app preview](/files/-LvLnQaJ7iEGS2XB6Ths)

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

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

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

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

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

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

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

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

## Actions

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

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

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

```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
  }
}

// я буду использовать синтаксис function внутри actions, так как не вижу смысла
// в изменении его на такую запись:

const getPhotos = (year) => ({
  type: GET_PHOTOS,
  payload: year,
})
```

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

## Reducer

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

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

Для того, чтобы научиться комбинировать редьюсеры, мы добавим в приложение reducer - *user*, который просто будет отображать имя, если пользователь залогинился. Ниже на схеме - сноска \[1].

Схематично, наше приложение можно представить так:

![redux-schema-with-reducers](/files/-LvLnR-W9jzjgD0-Kn6y)

Так как у нас есть 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.photos`

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

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

**Итого**: Redux - однонаправленный поток данных в вашем приложении. Случилось действие от юзера - полетел экшен, экшен был пойман редьюсером - изменились пропсы у React-компонента -> компонент перерисовался.


---

# 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/redux-course-ru-v2/sozdanie/osnovi-redux-teoriya.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.
