Por se tratar de uma biblioteca, o React é agnóstico e permite que existam diversos caminhos felizes para sua aplicação, sendo assim é comum a existência de dependências externas para controle do estado global integrados ao seu ecossistema.

Durante a concepção do React não havia uma receita de bolo para controlar o estado global de forma integrada ao sistema e muito menos recurso disponível ou implementado. O caminho sugerido para aplicações em grande escala era o Flux que foi criado pelo próprio Facebook, não era só para controle de estado global e sim para atender aplicações de grande porte. Sendo assim faz sentido usar o Flux para qualquer aplicação? Não tentem matar uma formiga com uma bazuca.

Durante a evolução do React surgiram bibliotecas com motivações de padronizar a comunicação entre os componentes e o contexto externo, seja uma requisição ou um banco local. Existem duas bibliotecas que trabalham para resolver um problema em comum, porém com abordagens diferentes o Redux e MobX.

Redux

Criado em 2015 por Dan Abramov e Andrew Clark  seu próprio nome o traduz o funcionamento que é baseado em funções reduce para manter o estado global. Apesar de inspirado no Flux, traz a simplicidade unificando tudo em um único store, o Redux pode facilitar o desenvolvimento, teste e debug das aplicações, já que toda mudança de estado global é disparada por uma action que por sua vez invoca reducers impactando na mudança do estado.

Apesar de bem documentado e robusto, o Redux, não é bala de prata, o próprio criador do Redux escreveu um artigo sugerindo que comece o projeto com React para entender se as necessidades do projeto podem ser resolvidas pelo Redux.

"Instead learn to think in React. Come back to Redux if you find a real need for it, or if you want to try something new. But approach it with caution, just like you do with any highly opinionated tool."

Referências: You Might Not Need Redux - Dan Abramov

Prós

  • Convenções que levam a adoção de padrões;
  • Estado imutável, imutabilidade é um conceito difundido em programação funcional, cada ação resulta em um novo estado. O Redux mantém uma cópia de cada estado isolando de qualquer hack que você queira fazer;
  • Time Travel, como cada ação reflete em um novo estado é possível viajar no tempo, como desfazer ações e até mesmo refazer;
  • Suporte, Dan Abramov trabalha no Facebook sendo assim podemos garantir que haverá suporte parcial da equipe React;
  • Dev Tools, há diversas extensões que permitem monitorar e depurar mudanças de estado;

Contras

  • Verboso - Não é muito difícil tornar o projeto verborrágico já que estamos falando de actions, reducers, states, selectors e outros milhões de helpers e pacotes que seu projeto provavelmente tem dependência;
  • Boilerplate, muitas vezes a falta de um pode induzir ao erro;
  • Curva de aprendizagem, não é tão intuitivo para desenvolvedores que vieram da orientação a objeto, entretanto para quem trabalha com funcional é bem claro;

MobX

Patrocinado por empresas conceituadas como Algolia, Coinbase e Facebook Open Source, o MobX é uma alternativa para o controle do estado global utilizando processos reativos. Assim como o Redux não é específico para React, é compatível com outras bibliotecas ou frameworks como Angular e Vue.

É divido em quatro partes:

  • Observable state, qualquer tipo de valor pode ser mutável seja primitivo ou complexo;
  • Computed values, valores computáveis podem ser concatenação de string ou seletores;
  • Reactions, semelhante a um valor computado, em vez de produzir um novo valor, produz um efeito colateral. Este efeito pode ser a mudança de dados que pode resultar em alguma mudança no DOM;
  • Actions, são os principais meios para modificar o estado;

Prós

  • Curva de aprendizagem, os Stores do Mobx são reativos ou seja você pode manipular diversos tipos de objetos e o MobX irá cuidar da renderização por causa dos Observables;
  • Menos verboso, já que você não escreve Actions + Reducers no padrão Redux, há um ganho neste quesito;
  • Sem middleware, por trabalhar de outra forma não há a necessidade de utilizar middleware como o Thunk para ações assíncronas;
  • Store flexível, além de manter dados o Store pode ser qualquer coisa desde uma classe proxy que depende de uma API;
  • Dev Tools, assim como o Redux há extensões para Chrome e Firefox, ótimo para acompanhar as mudanças de estado;

Contras

  • Interpretação, por ser muito simples podemos encontrar equívocos de implementação;
  • Renderização, como há reatividade podem ocorrer renderizações em massa impactando na performance, sendo assim use o Observable com moderação.

Show me the code

Apenas para comparação e experiência criei duas implementações Redux e Mobx.

O projeto é um TODO-LIST utilizando o Parcel.js como bundler para facilitar e simplificar o trabalho.

Serão exibidas partes principais da implementação, o código completo pode ser visualizado no GitHub.

import { combineReducers } from 'redux'
import { ADD_TASK, CLEAR_TASKS, TOGGLE_TASK, FILTER_TASKS } from './../actions/todoList'

const initialState = {
  tasks: [],
  filters: {
    status: null
  }
}

const todoList = (state = initialState, action) => {
  switch (action.type) {
    case ADD_TASK:
      return {
        ...state,
        tasks: [ ...state.tasks, action.task ]
      }
    default:
      return state
  }
}

const todoListReducer = combineReducers({
  todoList
})

export default todoListReducer

Redux

Actions

export const ADD_TASK = 'ADD_TASK'

export const addTask = task => {
  return {
    type: ADD_TASK,
    task
  }
}

Reducers

Components

//app.jsx
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { ToDoListComponent } from './todoList'
import store from './store'

render(
  <Provider store={store}>
    <ToDoListComponent />
  </Provider>,
  document.getElementById('root')
)

//main.jsx
import React from 'react'
import { connect } from 'react-redux'
import { addTask, toggleTask, clearTasks, filterTasks } from '../actions/todoList'
import { getTasks } from '../selectors'

const Home = () => {
  const handleClear = () => clearTasks()
    
  // ...
  return (
    <section>
    </section>
  )
}

const mapStateToProps = (state, _ownProps) => ({
  tasks: getTasks(state)
})

const mapDispatchToProps = (dispatch, _ownProps) => ({
  addTask: task => dispatch(addTask(task))
})

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Home)

Mobx

Store

import { action, observable, computed } from 'mobx'

class TasksStore {
  @observable data = []

  @observable filter = null

  @action setFilter = filter => { this.filter = filter }

  @action addTask (task) {
    this.data.push(task)
  }

  getTasks (filter) {
    return this.filter === null
      ? this.data
      : this.data.filter(x => x.done === filter)
  }

  @computed get tasks () {
    return this.getTasks(this.filter)
  }
}

export default TasksStore

Component

//app.jsx
import React from 'react'
import { render } from 'react-dom'
import { configure } from 'mobx'
import { ToDoListComponent } from './todoList'
import { appStore } from './store'
import DevTools from 'mobx-react-devtools'

configure({ enforceActions: 'always' })

render(
  <div>
    <DevTools />
    <ToDoListComponent store={appStore} />,
  </div>,
  document.getElementById('root')
)

//main.jsx
import React from 'react'
import ToDoListInput from './input'
import ToDoListTasks from './tasks'
import ToDoListFooter from './footer'

const Home = props => {
  const handleClear = () => props.store.tasks.clearTasks()
  // ...

  return (
    <section>
    </section>
  )
}

export default Home

Rodando

Aqui estão as implementações publicadas no Surge, não é só mostrar o código, quero ver funcionar rs.

Conclusão

Neste exemplo podemos encontrar as convenções do Redux e uma lado verboso comparado ao MobX. Fica bem claro que cada biblioteca trabalha de maneira diferente, resumidamente o MobX apoia a reatividade e o Redux abraça a programação funcional utilizando fortemente a imutabilidade.

Na concepção de um projeto React, se há uma nível de experiência da equipe em projetos com Vue ou Angular, penso que o MobX se encaixa melhor na minha opinião.

As convenções Redux ajudam os desenvolvedores a não reinventar a roda, é muito comum encontrar a combinação React + Redux, já que há uma forte comunidade, entretanto é possível encontrar projetos onde Redux não deveria estar, por este motivo peço que comparem qual abordagem facilitaria manutenção e tornaria o código limpo.

Código Fonte