Вам нужен Mobx или Redux?

React.js Redux MobX

В прошлом году все больше и больше проектов продолжали или начали использовать React и Redux для разработки, что является распространенным решением для фронтенд-проектов в индустрии фронтенда, но с развитием все большего количества проектов, все более и более разнообразных Иногда люди имеют разные чувства и мысли. Это потому, что у нас уже есть относительно распространенный и знакомый стек проектных технологий, мы его полностью используем, есть ли более подходящее решение, чем он? Случилось так, что у команды недавно появился новый проект, поэтому блогер начал думать, а можно ли использовать другие альтернативные технологии для разработки? Это может не только повысить эффективность разработки, но и расширить технические резервы и видение.После исследований я выбрал Mobx и, наконец, использовал React+Mobx для создания нового проекта.Эта статья обобщает и делится относительно полным процессом от выбора технологии до реализации проекта, надеясь добиться прогресса вместе.

Добро пожаловать в мой личный блог

предисловие

Когда мы используем React для разработки веб-приложений, внутри компонентов React мы можем использоватьthis.setState()иthis.stateОбработка или доступ к состоянию внутри компонента, но по мере того, как проект становится больше, а состояние усложняется, обычно необходимо учитывать связь между компонентами, в основном включая следующие два момента:

  1. Определенное состояние должно быть общим (доступным, обновленным) между несколькими компонентами;
  2. Взаимодействия внутри компонента должны запускать обновления состояния других компонентов;

Что касается этих проблем, практика разработки компонентов React рекомендует продвигать состояние общедоступного компонента:

Often, several components need to reflect the same changing data. We recommend lifting the shared state up to their closest common ancestor

Часто нескольким компонентам необходимо обрабатывать одно и то же состояние, и мы рекомендуем повышать общее состояние до их общего ближайшего компонента-предка.Подробнее

Когда проект становится более сложным, мы обнаруживаем, что простое улучшение состояния уже не может адаптироваться к такому сложному управлению состоянием, и состояние программы становится сложнее синхронизировать, оперировать и вызывать, публиковать и подписываться повсюду, а это значит, что мы нужен лучший метод управления состоянием, поэтому вводится библиотека управления состоянием, напримерRedux,Mobx,Jumpsuit,Alt.jsЖдать.

государственное управление

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

  1. Единое обслуживание и управление статусом приложений;
  2. Существует только один источник доверенных данных для состояния (обычно именуемый хранилищем, относящимся к контейнеру состояния);
  3. Способ работы с состоянием обновления един и управляем (обычно способ обновления состояния предоставляется в виде действия);
  4. Поддержка подключения магазина с компонентами React, такими какreact-redux,mobx-react; Обычно после использования библиотеки управления состоянием мы разделяем компоненты React на две категории от бизнеса:
    1. Компоненты-контейнеры: отвечают за обработку определенных бизнес-данных и данных о состоянии, а также за передачу функций обработки бизнеса или статуса в презентационные компоненты;
    2. Компоненты представления: отвечают за отображение представления и вызов входящей функции обработки в обратном вызове взаимодействия представления;

Mobx VS Redux

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

Mobx и Redux — это библиотеки управления состоянием приложений JavaScript, которые подходят для фреймворков или библиотек, таких как React, Angular, VueJs и т. д., а не ограничиваются конкретной библиотекой пользовательского интерфейса.

Redux

Чтобы представить Redux, мы должны поговорить о Flux:

Flux is the application architecture that Facebook uses for building client-side web applications.It's more of a pattern rather than a formal framework

Flux — это архитектура приложений Facebook для разработки клиент-серверных веб-приложений, и это скорее архитектурный шаблон, чем конкретная структура.Подробно объясните Flux.

Redux — это скорее реализация, которая следует шаблону Flux, Это библиотека JavaScript, которая фокусируется на следующих аспектах:

  1. Действие: объект JavaScript, который описывает информацию, связанную с действиями, в основном включающую атрибуты типа и атрибуты полезных нагрузок:
    1. Тип: Тип действия;
    2. полезная нагрузка: данные полезной нагрузки;
  2. Редуктор: определите, как состояние приложения реагирует на различные действия и как обновлять состояние;
  3. Store: объект, который управляет действиями и редюсерами и их отношениями, в основном предоставляя следующие функции:
    1. Поддерживать состояние приложения и поддерживать доступ к состоянию (getState());
    2. Поддерживает мониторинг распределения действий и обновление статуса (рассылка(действие));
    3. Поддержка изменений хранилища подписки (подписка (слушатель));
  4. Асинхронный поток: поскольку все изменения состояния хранилища в Redux должны инициироваться действиями, асинхронные задачи (обычно бизнес-задачи или задачи сбора данных) не являются исключением.Чтобы не смешивать бизнес-задачи или задачи, связанные с данными, в компоненты React, необходимо Необходимо использовать другие фреймворки для управления процессами асинхронных задач, такие какredux-thunk,redux-sagaЖдать;

Mobx

Mobx — это библиотека управления состоянием для прозрачного функционального реактивного программирования (TFRP), которая делает управление состоянием простым и масштабируемым:

Anything that can be derived from the application state, should be derived. Automatically.

Любые данные, происходящие из состояния приложения, должны извлекаться автоматически.

Его принцип показан на рисунке:

Mobx Philosophy

  1. Действие: определите функцию действия, которая изменяет состояние, включая способ изменения состояния;

  2. Магазин: централизованное управление состоянием модуля (State) и действием (action);

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

    1. Пользовательский интерфейс;

    2. производные данные;

      Существует два основных типа производных:

      1. Вычисляемые значения: вычисляемые значения всегда можно получить из текущего наблюдаемого состояния с помощью чистой функции;
      2. Реакции: Реакции относятся к побочным эффектам, которые должны происходить автоматически при изменении состояния.В этом случае нам необходимо реализовать его операции чтения и записи;
import {observable, autorun} from 'mobx';

var todoStore = observable({
    /* some observable state */
    todos: [],

    /* a derived value */
    get completedCount() {
        return this.todos.filter(todo => todo.completed).length;
    }
});

/* a function that observes the state */
autorun(function() {
    console.log("Completed %d of %d items",
        todoStore.completedCount,
        todoStore.todos.length
    );
});

/* ..and some actions that modify the state */
todoStore.todos[0] = {
    title: "Take a walk",
    completed: false
};
// -> synchronously prints: 'Completed 0 of 1 items'

todoStore.todos[0].completed = true;
// -> synchronously prints: 'Completed 1 of 1 items'

Функциональный и объектно-ориентированный

Redux больше следует идее функционального программирования (FP), тогда как Mobx рассматривает проблемы больше с объектно-ориентированной точки зрения.

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

(state, action) => {
  return Object.assign({}, state, {
    ...
  })
}

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

Дизайн Mobx более склонен к объектно-ориентированному программированию (ООП) и реактивному программированию (Reactive Programming), обычно упаковывая состояние в наблюдаемые объекты, поэтому мы можем использовать все возможности наблюдаемых объектов, как только объект состояния изменится, он может автоматически получить обновления.

Один магазин и несколько магазинов

Хранилище — это место, где приложение управляет данными.В приложениях Redux мы всегда централизуем все общие данные приложения в одном большом хранилище, в то время как Mobx обычно делит состояние приложения по модулям и управляет им в нескольких независимых хранилищах.

Объекты и наблюдаемые объекты JavaScript

Redux по умолчанию хранит данные как нативные объекты JavaScript, а Mobx использует наблюдаемые объекты:

  1. Redux необходимо вручную отслеживать изменения всех объектов состояния;
  2. Наблюдаемые объекты можно отслеживать в Mobx, и мониторинг будет автоматически запускаться при их изменении;

Неизменяемый и изменяемый

Объекты состояния Redux обычно неизменны:

switch (action.type) {
  case REQUEST_POST:
  	return Object.assign({}, state, {
      post: action.payload.post
  	});
  default:
    retur nstate;
}

Мы не можем напрямую манипулировать объектом состояния, но всегда возвращаем новый объект состояния на основе исходного объекта состояния, так что предыдущее состояние приложения может быть легко возвращено; и Mobx может напрямую обновлять объект состояния новым значением.

mobx-реакция и реакция-редукс

При подключении к приложениям Redux и React вам необходимо использоватьreact-reduxкоторый предоставилProviderиconnect:

  1. Provider: отвечает за внедрение Store в приложение React;
  2. connect: отвечает за внедрение состояния хранилища в компоненты контейнера и выбор определенных состояний для передачи в качестве свойств компонента контейнера;

Для Mobx требуются те же два шага:

  1. Provider:использоватьmobx-reactкоторый предоставилProviderвнедрить все магазины в приложение;
  2. использоватьinjectвнедрить конкретное хранилище в компонент, хранилище может передать состояние или действие; затем используйтеobserverУбедитесь, что компоненты могут реагировать на наблюдаемые изменения в хранилище, то есть сохранять обновления, а представления компонентов обновляются в ответ.

Причина выбора MOBX

  1. Низкая стоимость обучения: базовые знания MOBX очень просты. После изучения официальной документации и примерного кода на полчаса построен новый экземпляр проекта; в то время как Redux действительно более громоздкий и имеет много процессов. Это необходимо настроить, создавать Магазин, напишите редуктор и действие. Задача, также нужно представитьredux-thunkилиredux-sagaНаписание дополнительного кода, процесс Mobx намного проще, и не требует дополнительных библиотек асинхронной обработки;
  2. Объектно-ориентированное программирование: Mobx поддерживает объектно-ориентированное программирование, мы можем использовать@observable and @observer, делая объекты JavaScript отзывчивыми в объектно-ориентированном программировании; Redux больше всего рекомендует следовать функциональному программированию, и, конечно же, Mobx также поддерживает функциональное программирование;
  3. Меньше кода шаблона: по сравнению с различными кодами шаблонов Redux, такими как actionCreater, reducer, saga/thunk и т. д., Mobx не нужно писать такой код шаблона;

Возможные причины не выбирать Mobx

  1. Слишком много свободы: Mobx предоставляет несколько конвенций и кодов шаблонов, что делает код разработки очень свободным для написания. Если некоторые конвенции не сделаны, легко привести к которому стиль кода команды будет несовместимым, поэтому, когда есть много членов команды, Это действительно необходимо, чтобы добавить некоторые конвенции;
  2. Масштабируемость и ремонтопригодность: может быть, вас беспокоит, сможет ли Mobx адаптироваться к разработке более поздних проектов? Это правда, что Mobx больше подходит для использования в небольших и средних проектах, но это не значит, что он не может поддерживать крупномасштабные проекты, ключевой момент в том, что крупномасштабные проекты обычно требуют особого внимания к масштабируемости и ремонтопригодности. По сравнению с ним стандартизированный Redux имеет больше преимуществ: Mobx более свободен, и нам нужно самим сформулировать некоторые правила, чтобы обеспечить последующее расширение проекта и сложность обслуживания;

сравнение кода

Затем мы используем Redux и Mobx, чтобы просто реализовать одно и то же приложение, сравнить его код и посмотреть, как работает каждое из них.

Архитектура

В приложении Redux нам сначала нужно настроить, создать хранилище и использоватьredux-thunkилиredux-sagaпромежуточное ПО для поддержки асинхронных действий, затем используйтеProviderВставьте магазин в приложение:

// src/store.js
import { applyMiddleware, createStore } from "redux";
import createSagaMiddleware from 'redux-saga'
import React from 'react';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import { composeWithDevTools } from 'redux-devtools-extension';
import rootReducer from "./reducers";
import App from './containers/App/';

const sagaMiddleware = createSagaMiddleware()
const middleware = composeWithDevTools(applyMiddleware(sagaMiddleware));

export default createStore(rootReducer, middleware);

// src/index.js
…
ReactDOM.render(
  <BrowserRouter>
    <Provider store={store}>
      <App />
    </Provider>
  </BrowserRouter>,
  document.getElementById('app')
);

Приложения Mobx могут напрямую внедрять все хранилища в приложение:

import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'mobx-react';
import { BrowserRouter } from 'react-router-dom';
import { useStrict } from 'mobx';
import App from './containers/App/';
import * as stores from './flux/index';

// set strict mode for mobx
// must change store through action
useStrict(true);

render(
  <Provider {...stores}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>,
  document.getElementById('app')
);

Внедрить реквизит

Редукс:

// src/containers/Company.js
…
class CompanyContainer extends Component {
  componentDidMount () {
    this.props.loadData({});
  }
  render () {
    return <Company
      infos={this.props.infos}
      loading={this.props.loading}
    />
  }
}
…

// function for injecting state into props
const mapStateToProps = (state) => {
  return {
    infos: state.companyStore.infos,
    loading: state.companyStore.loading
  }
}

const mapDispatchToProps = dispatch => {
  return bindActionCreators({
      loadData: loadData
  }, dispatch);
}

// injecting both state and actions into props
export default connect(mapStateToProps, { loadData })(CompanyContainer);

Моб.:

@inject('companyStore')
@observer
class CompanyContainer extends Component {
  componentDidMount () {
    this.props.companyStore.loadData({});
  }
  render () {
    const { infos, loading } = this.props.companyStore;
    return <Company
      infos={infos}
      loading={loading}
    />
  }
}

Определить действие/редуктор и т. д.

Редукс:

// src/flux/Company/action.js
…
export function fetchContacts(){
  return dispatch => {
    dispatch({
      type: 'FREQUEST_COMPANY_INFO',
      payload: {}
    })
  }
}
…

// src/flux/Company/reducer.js
const initialState = {};
function reducer (state = initialState, action) {
  switch (action.type) {
    case 'FREQUEST_COMPANY_INFO': {
      return {
        ...state,
        contacts: action.payload.data.data || action.payload.data,
        loading: false
      }
    }
    default:
      return state;
  }
}

Mobx:

// src/flux/Company/store.js
import { observable, action } from 'mobx';

class CompanyStore {
  constructor () {
    @observable infos = observable.map(infosModel);
  }

  @action
  loadData = async(params) => {
    this.loading = true;
    this.errors = {};
    return this.$fetchBasicInfo(params).then(action(({ data }) => {
      let basicInfo = data.data;
      const preCompanyInfo = this.infos.get('companyInfo');
      this.infos.set('companyInfo', Object.assign(preCompanyInfo, basicInfo));
      return basicInfo;
    }));
  }

  $fetchBasicInfo (params) {
    return fetch({
      ...API.getBasicInfo,
      data: params
    });
  }
}
export default new CompanyStore();

Асинхронное действие

Если вы используете Redux, нам нужно дополнительно добавитьredux-thunkилиredux-sagaДля поддержки асинхронного действия, которое требует дополнительной настройки и написания кода шаблона, Mobx не требует дополнительной настройки.

Основной код redux-saga:

// src/flux/Company/saga.js
// Sagas
// ------------------------------------
const $fetchBasicInfo = (params) => {
  return fetch({
    ...API.getBasicInfo,
    data: params
  });
}

export function *fetchCompanyInfoSaga (type, body) {
  while (true) {
    const { payload } = yield take(REQUEST_COMPANY_INFO)
    console.log('payload:', payload)
    const data = yield call($fetchBasicInfo, payload)
    yield put(receiveCompanyInfo(data))
  }
}
export const sagas = [
  fetchCompanyInfoSaga
];

некоторые мысли

Независимо от фронтенда или бэкенда, если вы сталкиваетесь с проблемами, большую часть времени, может быть, все привыкли рекомендовать те, которые широко раскручены и используются. надо думать дальше, а правильный лучше.

Конечно, мы также должны избегать таких умозаключений, как «Redux более стандартизирован и надежен, вам следует использовать Redux» или «Шаблонов Redux слишком много, они слишком сложны, вам следует выбрать Mobx», это относительные термины, у каждого фреймворка есть свои особенности. свою собственную реализацию, характеристики и применимые сценарии.Например, процесс Redux более сложен, но после ознакомления с процессом вы сможете лучше понять некоторые из его основных/основных концепций, и у вас может быть больше опыта и восприятия при использовании это; в то время как Mobx упрощен, большая часть его скрыта, и его основные / основные идеи не могут быть доступны без специального исследования, которое может удерживать разработчиков на уровне использования.

Итак, будь то стек технологий или фреймворк. Библиотеки классов, тут нет абсолютного сравнения, что выбрать, а от чего отказаться, следует больше обращать внимание на то, какие задачи они решают, их направленность на решение задач, или каков метод реализации, каковы их преимущества и недостатки, какой из них больше подходит для текущего проекта и будущего развития проекта.

Ссылаться на

  1. An in-depth explanation of Mobx
  2. Redux & Mobx
  3. Mobx
  4. Redux vs Mobx