Основы Redux (теория)¶
Курс рассчитан на создание приложения по шагам, а это значит максимум практики и минимум теории. Этот самый минимум, перед вами.
Давайте еще раз взглянем на схему нашего приложения:
В шапке слева заголовок и три кнопки выбора года. Ниже - фото соответствующего года, отсортированное по количеству лайков.
В шапке справа - ссылка войти/выйти.
Представим, как должны выглядеть данные для такой страницы:
1 2 3 4 5 6 7 8 9 10 |
|
Поздравляю вас, мы только что описали как должно выглядеть состояние (state
) нашего приложения.
За содержание всего состояния нашего приложения, отвечает объект Store
. Как уже не раз упоминалось - это обычный объект {}
. Важно, что в отличии от Flux, в Redux только один объект Store
.
Не хочется оставлять вас надолго без практики, поэтому процесс создания store
и немного подробностей про него я аккуратно вплету в следующие главы, а пока достаточно того, что: store
, "объединяет" редьюсер(ы) (reducer
) и действия (actions
), а так же имеет несколько чрезвычайно полезных методов, например:
getState()
- позволяет получить состояние приложения;dispatch(action)
- позволяет обновлять состояния, путем вызова ("диспатча") действия;subcribe(listener)
- регистрирует слушателей;
Actions¶
Actions описывают действия.
Actions - это объект. Обязательное поле - type
. Так же, если вы хотите следовать соглашению, все данные, которые передаются вместе с действием, кладите внутрь свойства payload
. Таким образом, для нашего приложения, мы можем составить, например такую пару действий (actions
):
1 2 3 4 |
|
1 2 3 4 |
|
Чтобы вызвать actions
, мы должны написать функцию, которая в рамках Flux/Redux называется - ActionsCreator
(создатель действия), но перед этим стоит принять во внимание, что обычно тип действия, описывают как константу.
Например, константы нашего проекта:
1 2 |
|
Не все любят данный подход с константами, но он был родоначальником, плюс его легко объяснить. К тому же, я до сих пор сторонник этого подхода.
Вернемся к ActionsCreator
, один из наших "создателей действий", выглядел бы так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Итого: actions сообщает нашему приложению - "Эй, что-то произошло! И я знаю, что именно!"
Reducer¶
"Actions описывает факт, что что-то произошло, но не указывает, как состояние приложения должно измениться в ответ, это работа для Reducer'а" - (офф. документация)
Наше приложение не нуждается в нескольких редьюсерах, но крайне необходимо познакомить читателя с reducer composition, так как это фундаментальный шаблон построения redux приложений: мы разбиваем наше глобальное состояние на кусочки, за каждый кусочек отвечает свой reducer
. Кусочки объединяются в Корневом Редьюсере (rootReducer
).
Для того, чтобы научиться комбинировать редьюсеры, мы добавим в приложение reducer - user, который просто будет отображать имя, если пользователь залогинился. Ниже на схеме - сноска 1.
Схематично, наше приложение можно представить так:
Так как у нас есть reducer'ы page
и user
, можно представить следующий диалог:
1 2 |
|
А на js выглядело бы так:
1 2 3 4 5 6 7 8 9 10 |
|
Обратите внимание, мы не мутировали наш state
, мы создали новый state
. Это важно. Крайне важно. В редьюсере, мы всегда должны возвращать новый объект, а не измененный предыдущий.
На практике, я буду использовать object spread syntax, поэтому предыдущую функцию с Object.assign
можно переписать следующим образом:
1 2 3 4 5 6 7 8 |
|
Объект, который мы возвращаем в редьюсере, далее с помощью функции connect
, превратится в свойства для компонентов. Таким образом, если продолжить пример с фото, то можно написать такой псевдо-код:
1 |
|
Благодаря этому, внутри компонента <Page />
, мы сможем получить фото, как this.props.photos
Итого: Redux - однонаправленный поток данных в вашем приложении. Случилось действие от юзера - полетел экшен, экшен был пойман редьюсером - изменились пропсы у React-компонента -> компонент перерисовался.