Redux против MobX без путаницы

image

В последние годы я часто использовал Redux, но в последнее время использую MobX в качестве альтернативы управления состоянием. Кажется, что альтернативы Redux естественно превращаются в беспорядок. Люди не уверены, какое решение выбрать. Проблема не обязательно «Redux vs MobX». Всякий раз, когда существует альтернатива, людям любопытно, как лучше всего решить их проблему. Я пишу эти строки, чтобы устранить путаницу вокруг решений по управлению состояниями Redux и MobX.

О чем будет эта статья? Во-первых, я хочу вкратце вернуться к проблеме, которую решает библиотека управления состоянием. В конце концов, все будет хорошо, если вы просто используете this.setState() и this.state в React или его вариацию в другой библиотеке уровня представления или в среде SPA. Во-вторых, я буду продолжать давать вам обзор обоих решений, показывая последовательность и различия. И последнее, но не менее важное: если у вас уже есть приложение, работающее с MobX или Redux, я хочу рассказать вам о рефакторинге из одной в другую библиотеку управления состояниями.

Содержание:


  1. Какую проблему мы решаем?
  2. В чем разница между REDUX и MOBX?
  3. Кривая обучения состоянием React
  4. Последние мысли по теме
  5. Больше ресурсов



Какую проблему мы решаем?


Все хотят иметь управление состоянием в приложении. Но какую проблему это решает для нас? Большинство людей начинают с небольшого приложения и уже внедряют библиотеку управления состоянием. Все об этом говорят, не так ли? Redux! MobX! Но большинство приложений не нуждаются в амбициозном управлении состояниями с самого начала. Это еще более опасно, потому что большинство людей никогда не столкнутся с тем, какие проблемы решают такие библиотеки, как Redux или MobX.

В настоящее время статус-кво заключается в построении фронтенд-приложения с компонентами. Компоненты имеют внутреннее состояние. В растущем приложении управление состоянием может стать хаотичным с локальным состоянием, поскольку:

  • компонент должен делиться состоянием с другим компонентом
  • компонент должен видоизменить состояние другого компонента

В какой-то момент становится все сложнее и сложнее рассуждать о состоянии приложения. Это становится грязной паутиной объектов состояния и мутаций состояний в вашей иерархии компонентов. В большинстве случаев объекты состояния и мутации состояния не обязательно связаны с одним компонентом. Они связаны через ваше дерево компонентов, и вы должны поднимать и опускать состояние.

Решение, таким образом, состоит в том, чтобы ввести библиотеку управления состоянием, такую как MobX или Redux. Она дает вам инструменты для сохранения вашего состояния, изменения состояния и получения обновлений состояния. У вас есть одно место для поиска, одно место для изменения и одно место для получения обновлений состояния. Он следует принципу единого источника правды. Это облегчает рассуждения об изменениях вашего состояния и состояний, потому что они отделяются от ваших компонентов.

Библиотеки управления состоянием, такие как Redux и MobX, часто имеют дополнения к утилитам, например, для Angular они имеют angular-redux и mobx-angular, чтобы дать вашим компонентам доступ к состоянию. Часто эти компоненты называют контейнерными компонентами или, если быть более точным, связанными компонентами. Из любой точки вашей иерархии компонентов вы можете получить доступ к состоянию и изменить его, обновив свой компонент до связанного.

В чем разница между REDUX и MOBX?


Перед тем, как мы погрузимся в разницу, я хочу рассказать вам о схожести между MobX и Redux.

Обе библиотеки используются для управления состоянием в JavaScript-приложениях. Они не обязательно связаны с такой библиотекой, как Angular. Они также используются в других библиотеках, таких как ReactJs и VueJs.

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

Redux разработанный Дэном Абрамовым и Эндрю Кларком является производным архитектуры Flux. В отличие от Flux, он использует одно хранилище над несколькими для сохранения состояния. Кроме того, вместо диспетчера он использует чистые функции для изменения состояния. Если вы не знакомы с потоком и вы новичок в управлении состоянием, не беспокойтесь о последнем абзаце.

На Redux влияют принципы функционального программирования (FP). FP может быть сделано на JavaScript, но многие люди происходят из объектно-ориентированного фона, как Java, и имеют трудности в принятии принципов функционального программирования в первую очередь. Позже это объясняет, почему MobX может быть легче освоить как новичок.

Так как Redux включает в себя функциональное программирование, он использует чистые функции.
Чистая функция — функция которая получает вход, возвращает выход и не имеет других зависимостей, кроме таких же функций. Такая функция производит всегда один и тот же выход с одним и тем же входом и не имеет никаких побочных эффектов. Подробнее...

(state, action) => newState

Ваше состояние Redux является неизменным. Вместо того, чтобы мутировать, вы всегда возвращаете новое состояние. Вы не выполняете мутаций состояния и не зависите от ссылок на объекты.


// не делайте этого в Redux, потому что он мутирует массив
function addAuthor(state, action) {
  return state.authors.push(action.author);
}
// оставайтесь неизменным и всегда возвращайте новый объект
function addAuthor(state, action) {
  return [ ...state.authors, action.author ];
}

И последнее, но не менее важное: в идиоматическом Redux ваше состояние нормализовано, как в базе данных. Сущности ссылаются друг на друга только по id. Это лучшая практика. Несмотря на то, что не все так делают, вы можете использовать библиотеку типа normalizr для достижения такого нормализованного состояния. Нормализованное состояние позволяет вам сохранять плоское состояние и сущности как единый источник истины.

{
  post: {
    id: 'a',
    authorId: 'b',
    ...
  },
  author: {
    id: 'b',
    postIds: ['a', ...],
    ...
  }
}



Для сравнения, на MobX Мишеля Вестстрата влияет не только объектно-ориентированное программирование, но также и реактивное программирование. Он обертывает ваше состояние в наблюдаемые объекты. Таким образом, у вас есть все возможности "Observable" в вашем состоянии. Данные могут иметь простые сеттеры и геттеры, но наблюдаемое позволяет получать обновления после изменения данных.

В Mobx ваше состояние изменчиво. Таким образом, вы изменяете состояние напрямую:

function addAuthor(author) {
  this.authors.push(author);
}

Кроме того, организации остаются в (глубоко) вложенной структуре данных по отношению друг к другу. Вы не нормализуете свое состояние. Состояние остается денормализованным и вложенным.

{
  post: {
    id: 'a',
    ...
    author: {
      id: 'b',
      ...
    }
  }
}


Одно хранилище против нескольких


В Redux вы храните все свое состояние в одном глобальном хранилище или в одном глобальном состоянии. Единый объект состояния — ваш единственный источник правды. Многочисленные редукторы, с другой стороны, позволяют ему изменять неизменяемое состояние.

Для сравнения, MobX использует несколько хранилищ. Как и редукторы Redux, вы можете применять разделение и завоевание по техническим уровням, домену и т.п. Вы можете хранить свои доменные объекты в отдельных хранилищах, но также можете контролировать состояние просмотра в своих хранилищах. В конце концов, вы размещаете состояние, наиболее подходящее для вашего приложения.

Технически вы можете иметь несколько хранилищ и в Redux. Никто не заставляет вас использовать только одно. Но это не рекламируемый случай использования Redux. Использование нескольких хранилищ идет вразрез с лучшими практиками. В Redux вы хотите иметь одно хранилище, которое реагирует через свои редукторы на глобальные события.

Как выглядит реализация?


В Redux для добавления конфигурации приложения в глобальное состояние потребуются следующие строки кода.

interface IUsersState {
  users: IUsers;
}

const initialUsersState: IUsersState = {
  users: [
    {
      name:"Nikita"
    }
  ]
};

// reducer
const configReducers = (
  state = initialConfigState,
  action: UsersActions
): IUsersState => {
  switch (action.type) {
    case '[IUsers] Add Users': {
      return {
        ...state,
        users: [ ...state.users, action.user ]
      };
    }

    default:
      return state;
  }
};

// actions
class GetUsersSuccess implements Action {
  public readonly type = "[IUsers] Add Users";
  constructor(public payload: IUsers) {}
}

В MobX хранилище будет управлять только подсостоянием (как редуктор в Redux управляет подсостоянием), но вы можете напрямую изменять состояние. Аннотация @observable позволяет наблюдать изменения состояния.

class userStore{
@observable users = [
    {
      name: 'Nikita'
    }
  ];
}

Теперь можно вызывать userStore.users.push (user); на экземпляре магазина. Тем не менее, рекомендуется сохранять мутации состояния более явными с помощью действий.

class userStore{
@observable users = [
    {
      name: 'Nikita'
    }
  ];
}
@action addUser = (user) => {
    this.users.push(user);
  }


Вы можете строго применить его, настроив MobX с помощью configure ({empceActions: true}) ;. Теперь вы можете изменить свое состояние, вызвав userStore.addUser (user); на экземпляре магазина.

Вы видели, как обновлять состояние как в Redux, так и в MobX. В Redux ваше состояние доступно только для чтения. Вы можете изменить состояние только с помощью явных действий. В отличие от этого, в MobX состояние включает чтение и запись. Вы можете мутировать состояние напрямую, не используя действия, но вы можете выбрать явные действия, используя конфигурацию принудительных действий (enforceActions).

Кривая обучения состоянием React



И Redux, и MobX в основном используются в приложениях React. Но это автономные библиотеки для управления состоянием, которые можно использовать везде без React. Их библиотеки взаимодействия позволяют легко комбинировать их с компонентами Angular. Это react-redux для React + Redux и mobx-react для React + MobX. Позже я объясню, как использовать оба в дереве компонентов Angular.

В недавних дискуссиях случалось так, что люди спорили о кривой обучения в Redux. Часто это происходило в контексте React: люди начали изучать React и уже хотели использовать управление состоянием с Redux. Большинство людей утверждают, что React и Redux сами имеют хорошую кривую обучения, но оба вместе могут быть ошеломляющими. Поэтому альтернативой будет MobX, потому что он больше подходит для начинающих.

Тем не менее, я бы предложил другой подход для начинающих пользователей React для изучения управления состоянием в экосистеме React. Начните изучать React со своими собственными локальными функциями управления состоянием в компонентах. В приложении React вы сначала изучите методы жизненного цикла React и разберетесь с управлением локальными состояниями с помощью setState () и this.state. Я очень рекомендую этот путь обучения. В противном случае вы будете быстро перегружены экосистемой React. В конце концов, на этом пути вы поймете, что управление (внутренним) состоянием компонентов становится сложным.

Redux или MobX для новичков?


Ознакомившись с компонентами Angular и внутренним управлением состоянием, вы можете выбрать библиотеку управления состоянием для решения вашей проблемы. После того, как я использовал обе библиотеки, я бы сказал, что MobX может быть очень удобен для начинающих. Мы уже убедились, что MobX нуждается в меньшем количестве кода, хотя и использует некоторые магические примечания, о которых нам пока знать не обязательно.
В MobX Вам не нужно быть знакомым с функциональным программированием. Такие термины, как неизменяемость, могут быть все еще иностранными.
Функциональное программирование — это растущая парадигма, но новая для большинства людей в JavaScript. Существует четкая тенденция к этому, но так как не у всех есть опыт функционального программирования, людям с объектно-ориентированным фоном, возможно, будет проще принять принципы MobX.


Переход на Redux


Как только ваше приложение станет больше и над ним будут работать несколько разработчиков, вам следует подумать об использовании Redux. По своей природе он обязуется использовать явные действия для изменения состояния. Действие имеет тип и полезную нагрузку, которые редуктор может использовать для изменения состояния. В команде разработчиков очень легко рассуждать об изменениях состояния таким образом.

Redux предоставляет вам целую архитектуру для управления состоянием с четкими ограничениями. История успеха Redux.

Еще одним преимуществом Redux является использование его на стороне сервера. Поскольку мы имеем дело с простым JavaScript, вы можете отправить состояние по сети. Сериализация и десериализация объекта состояния работает из коробки. Тем не менее, это возможно и в MobX.

MobX менее самоуверен, но с помощью configure ({ empceActions: true }) вы можете применять более четкие ограничения, как в Redux. Вот почему я бы не сказал, что вы не можете использовать MobX для масштабирования приложений, но в Redux есть четкий способ сделать что-то. Документация в MobX даже гласит: «[MobX] не говорит вам, как структурировать ваш код, где хранить состояние или как обрабатывать события». Команда разработчиков должна была бы сначала создать архитектуру управления государством.

В конце концов, кривая изучения государственного управления не так крута. Когда мы повторим рекомендации, новичок в React сначала научится правильно использовать setState () и this.state. Через некоторое время вы поймете проблемы использования только setState () для поддержания состояния в приложении React. При поиске решения вы сталкиваетесь с библиотеками управления состояниями, такими как MobX или Redux. Но какой выбрать? Поскольку MobX менее самоуверен, имеет меньший шаблон и может использоваться аналогично setState (), я бы порекомендовал в небольших проектах дать MobX шанс. Как только приложение увеличится в размере и увеличит количество участников, вы должны рассмотреть возможность применения дополнительных ограничений в MobX или дать Redux шанс. Мне понравилось использовать обе библиотеки. Даже если вы не используете один из них в конце концов, имеет смысл увидеть альтернативный способ управления состоянием.

Последние мысли


Всякий раз, когда я читаю комментарии в обсуждении Redux против MobX, всегда есть один комментарий: «В Redux слишком много стандартного образца, вместо этого вы должны использовать MobX. Я смог удалить XXX строк кода». Комментарий может быть правдой, но никто не считает компромисс. Redux поставляется с большим количеством шаблонов, таких как MobX, потому что он был добавлен для конкретных конструктивных ограничений. Это позволяет вам рассуждать о состоянии вашего приложения, даже если оно в более широком масштабе. Вся церемония, связанная с обработкой состояния, проходит не просто так.

Библиотека Redux довольно маленькая. Большую часть времени вы имеете дело только с простыми объектами и массивами JavaScript. Это ближе к ванильному JavaScript, чем MobX. В MobX объекты и массивы оборачиваются в наблюдаемые объекты, которые скрывают большую часть стандартного шаблона. Он строится на скрытых абстракциях в которых происходит волшебство, но труднее понять основные механизмы. В Redux легче рассуждать об этом с помощью простого JavaScript. Это облегчает тестирование и отладку приложения.

Кроме того, нужно еще раз подумать, откуда мы пришли в SPA. Куча одностраничных фреймворков и библиотек приложений имела те же проблемы управления состоянием, которые в конечном итоге были решены с помощью всеобъемлющей модели потоков. Redux является преемником такого подхода.

В MobX он снова движется в обратном направлении. Мы снова начинаем мутировать состояние напрямую, не используя преимущества функционального программирования. Для некоторых людей это снова приближается к двусторонней привязке данных. Через некоторое время люди могут снова столкнуться с теми же проблемами, прежде чем появилась библиотека управления состоянием, такая как Redux. Управление состоянием разбросано по компонентам и заканчивается беспорядком.

В то время как в Redux у вас есть установленная церемония настройки вещей, MobX менее самоуверен. Но было бы разумно принять лучший опыт в MobX. Люди должны знать, как организовать управление состоянием, чтобы улучшить аргументацию по этому поводу. Иначе люди склонны изменять состояние непосредственно в компонентах.

Обе библиотеки великолепны. Хотя Redux уже хорошо зарекомендовал себя, MobX становится действительной альтернативой для управления состоянием.


Больше ресурсов


сравнение Мишеля Вестстрата — создателя MobX
сравнение Прети Касиредди
Источник: habr.ru