Контейнер предсказуемого состояния для приложений JavaScript

Что такое Редукс?

  • Redux — это контейнер предсказуемого состояния, разработанный, чтобы помочь вам писать приложения JavaScript, которые одинаково ведут себя в клиентских, серверных и собственных средах и которые легко тестировать.
  • Redux был создан Дэном Абрамовым примерно в июне 2015 года. Он был вдохновлен Flux от Facebook и языком функционального программирования Elm. Redux очень быстро стал популярным из-за его простоты, небольшого размера (всего 2 КБ) и отличной документации.

Принципы редукса

Предсказуемость Redux определяется тремя наиболее важными принципами, указанными ниже:

  1. Единый источник достоверной информации.Состояние всего вашего приложения хранится в дереве объектов в одном хранилище. Поскольку все состояние приложения хранится в одном дереве, это упрощает отладку и ускоряет разработку.
  2. Состояние доступно только для чтения.Единственный способ изменить состояние — это выполнить действие, объект, описывающий, что произошло. Это означает, что никто не может напрямую изменить состояние вашего приложения.
  3. Изменения вносятся с помощью чистых функций.Чтобы указать, как дерево состояний преобразуется действиями, вы пишете чистые редукторы. Редуктор — это центральное место, где происходит изменение состояния. Редьюсер — это функция, которая принимает текущее состояние и действие для выполнения. Функция должна возвращать недавно обновленное состояние, а не измененную версию существующего состояния.

Строительные части Redux

Redux состоит из трех частей: действия, хранилище и редюсеры.

Действия в Redux

Короче говоря, действия — это события. Это единственный способ отправить данные из вашего приложения в магазин Redux. Данные могут быть получены из взаимодействия с пользователем, внутренних событий, таких как вызовы API, или даже отправки форм.

  • Действия — это простые объекты JavaScript, и они должны иметь свойство type (обычно постоянное), указывающее тип выполняемого действия. Они также должны иметь полезную нагрузку, содержащую информацию, над которой должно работать действие.
{ 
  type: "LOGIN",
  payload: {
    username: "Ayush",
    password: "12345"
  }
}
  • Действия создаются с помощью создателей действий. Это звучит очевидно, я знаю. Это просто функции, которые возвращают действия.
const setLoginStatus = (name, password) => {
  return {
    type: "LOGIN",
    payload: {
      username: "Ayush",
      password: "12345"
    }
  }
}
  • Действия отправляются методом store.dispatch().
store.dispatch(setLoginStatus(name, password));

Редукторы в Redux

Редьюсеры — это чистая функция в Redux. Чистые функции предсказуемы. Редьюсеры — единственный способ изменить состояние в Redux.

  • Это единственное место, где вы можете писать логику и расчеты. Функция редуктора примет предыдущее состояние приложения и отправляемого действия, рассчитает следующее состояние и вернет новый объект.
  • Следующие несколько вещей никогда не должны выполняться внутри редуктора: мутация аргументов функций, вызовы API и логика маршрутизации, а также вызов нечистой функции, например. Math.random()
  • Он основан на функции reduce в JavaScript, где одно значение вычисляется из нескольких значений после выполнения функции обратного вызова.
Redux reducer signature
(previousState, action) => nextState
Array.prototype.reduce signature
(accumulator, value) => (accumulator + value)
Example:
const handleAuth = (state = initialState, action) => {
    switch (action.type) {

      // This reducer handles any action with type "LOGIN"
      case "LOGIN":
          return state.map(user => {
              if (user.username !== action.payload.username) {
                  return user;
              }

              if (user.password == action.payload.password) {
                  return {
                      ...user,
                      login_status: "LOGGED IN"
                  }
              }
          });
        default:
          return state;
      } 
};
  • Как чистые функции, они не изменяют данные в переданном им объекте и не выполняют никаких побочных эффектов в приложении. Имея один и тот же объект, они всегда должны давать один и тот же результат.
  • Для более сложных приложений возможно использование утилиты combineReducers() , предоставляемой Redux (действительно, рекомендуется). Он объединяет все редукторы в приложении в один индексный редуктор. Каждый редьюсер отвечает за свою часть состояния приложения, и параметр состояния у каждого редьюсера разный. Утилита combineReducers() значительно упрощает обслуживание файловой структуры.
const rootReducer = combineReducers({
    handleAuth: handleAuth,
    editProfile: editProfile,
    changePassword: changePassword
});

Магазин в Редукс

Магазин — это неизменное дерево объектов в Redux. В хранилище хранится состояние приложения. Настоятельно рекомендуется хранить только одно хранилище в любом приложении Redux. Магазин имеет следующие обязанности:

  • Разрешает доступ к состоянию через getState();
  • Позволяет обновлять состояние через dispatch(action);
  • Регистрирует слушателей через subscribe(listener);
  • Обрабатывает отмену регистрации слушателей с помощью функции, возвращаемой subscribe(listener).
  • createStore-функция может иметь три аргумента. Редьюсер — это функция, которая возвращает следующее состояние приложения. PreloadedState — это необязательный аргумент, который является начальным состоянием вашего приложения. Энхансер также является необязательным аргументом. Это поможет вам расширить магазин сторонними возможностями.
Syntax - createStore(reducer, [preloadedState], [enhancer])
Example:
import { createStore } from ‘redux’;
import rootReducer from './reducers/index';
const store = createStore(rootReducer);
  • Действия, выполняемые над состоянием, всегда возвращают новое состояние через редьюсеры. Таким образом, состояние очень легкое и предсказуемое.
store.dispatch(setLoginStatus(‘alex’, ‘123456’));

Редукс — ПО промежуточного слоя

  • Сам Redux является синхронным, так как же асинхронные операции, такие как сетевые запросы, работают с Redux? Здесь пригодятся промежуточные программы.

  • Как обсуждалось ранее, редукторы — это место, где записывается вся логика выполнения. Редьюсер не имеет ничего общего с тем, кто его выполняет, сколько времени это занимает или регистрирует состояние приложения до и после отправки действия. В этом случае функция промежуточного программного обеспечения Redux предоставляет среду для взаимодействия с отправленным действием до того, как оно достигнет редюсера.
  • Обычно ПО промежуточного слоя используется для обработки асинхронных действий в вашем приложении. Redux предоставляет API под названием applyMiddleware, который позволяет нам использовать собственное промежуточное ПО, а также промежуточное ПО Redux, такое как redux-thunk и redux-saga. И это можно применить для хранения следующим образом:
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
const store = createStore(rootReducer, applyMiddleware(thunk));
  • Промежуточное программное обеспечение позволит вам написать диспетчер действий, который возвращает функцию вместо объекта действия.
function getUser() {
   return function() {
      return axios.get('/get_user_details');
   };
}
  • Технически промежуточное программное обеспечение — это функции, которые вызывают следующий метод, полученный в аргументе, после обработки текущего действия. Они вызываются после каждой отправки. Вот как выглядит простое промежуточное ПО:
Syntax - ({ getState, dispatch }) => next => action
function simpleMiddleware({ getState, dispatch }) {
  return function(next){
    return function(action){
      // processing
      const nextAction = next(action);
      // read the next state
      const state = getState();
      // return the next action or you can dispatch any other action
      return nextAction;  
    }
  }
}
const store = createStore(rootReducer , initialState=[ ] , applyMiddleware(simpleMiddleware));

Зачем использовать Redux?

  • Предсказуемость результата.Всегда есть один источник правды, хранилище, и нет путаницы в том, как синхронизировать текущее состояние с действиями и другими частями приложения.
  • Сопровождаемость.Предсказуемый результат и строгая структура облегчают поддержку кода. Это также поможет вам отделить бизнес-логику от дерева компонентов. Для крупномасштабных приложений очень важно, чтобы ваше приложение было более предсказуемым и ремонтопригодным.
  • Организация.Redux строже относится к организации кода, что делает код более согласованным и с ним проще работать команде.
  • Рендеринг на сервере.Это очень полезно, особенно для первоначального рендеринга, что позволяет улучшить взаимодействие с пользователем или оптимизировать поисковую систему. Просто передайте хранилище, созданное на сервере, на сторону клиента.
  • Инструменты для разработчиков. Разработчики могут отслеживать все, что происходит в приложении, в режиме реального времени, от действий до изменений состояния. Это дает вам возможность редактировать код в реальном времени в сочетании с отладчиком, путешествующим во времени.
  • Сообщество и экосистема.Это огромный плюс, когда вы изучаете или используете какую-либо библиотеку или фреймворк. Наличие сообщества позади Redux делает его еще более привлекательным в использовании.
  • Простота тестирования.Первое правило написания тестируемого кода — писать небольшие функции, которые делают только одну вещь и являются независимыми. Код Redux в основном состоит из таких функций: маленьких, чистых и изолированных.
  • Преимущества в производительности. Можно предположить, что сохранение глобального состояния приложения приведет к некоторому снижению производительности. В значительной степени это не так. React Redux реализует множество внутренних оптимизаций производительности, поэтому ваш собственный подключенный компонент выполняет повторную визуализацию только тогда, когда это действительно необходимо.

Redux DevИнструменты

  • Последним полезным шагом в работе с Redux является установка и запуск собственных инструментов разработки Redux. Если вы используете Chrome, вы можете включить Redux DevTools, перейдя по ссылке ниже:


  • Но есть еще один шаг, чтобы заставить его работать. В нашем методе createStore нам нужно передать в качестве аргумента после нашего редуктора следующее: window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()() . С этим дополнением store.js должно выглядеть так:
import { createStore } from 'redux';
import reducer from './reducers';
const store = createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
export default store;
  • Теперь мы сможем получить доступ к Redux DevTools из панели Chrome DevTools (нажав CTRL/CMD + Shift + I) и выбрав Redux.

Вывод

Мы узнали об основах, компонентах сборки и использовании Redux. А для реализации Redux с нуля вы можете прочитать эту статью —



Надеюсь, что после этого вы почувствуете себя более комфортно с Redux.
Спасибо за прочтение :)

Дополнительные материалы на codecrunch.org