Gerenciamento de estado com React

Victor Magalhães

Arthur Souza

React Salvador

Gerenciamento de estado?

Gerenciamento de estado

Estado é o conjunto de todos os valores armazenados por uma aplicação como propriedades ou variáveis em qualquer dado instante.

Back to the basics

  • React torna a UI uma função do estado da aplicação;

    • Imperativo x Declarativo
  • Estado de um componente: state e props;

  • Portanto, o estado de um componente é interno (state) ou enviado por seu pai direto (props);

Tipos de estado

  • Estado local: estado pertinente apenas para uma pequena porção da aplicação.

    • valor dos campos de um formulário, estado de um diálogo (aberto/fechado)
       

  • Estado global: estado pertinente para múltiplas partes desconexas da aplicação.

    • para uma app de tarefas, a lista de tarefas

Aplicação de exemplo

Gerenciando estado global com React

Mudando estado

Propagando mudanças

Problemas

  • Mudanças em um componente podem envolver modificar vários componentes acima dele;

    • Difícil de manter;

    • Difícil de avaliar de onde e pra onde o estado vai;

  • O estado pode ser duplicado e ficar desatualizado;

    • Armazenar lista das tarefas no estado de dois componentes;

    • Modificar uma das listas e não a outra;

Prop Drilling

Gerenciando estado global com stores

Mudando estado

Propagando mudanças

Vantagens

  • Fácil de avaliar quem usa o estado global

  • Somente os componentes que usam o estado são re-renderizados

  • Fácil de manter

  • Torna difícil duplicar estado

Como funciona

Ações - se comunicando com a store

const action = {
    type: "CREATE_TASK",
    data: {
        text: "Comprar ração de cachorro",
        dueDate: new Date(Date.now() + 24 * 60 * 60 * 1000),
        isDone: false,
    },
};

this.props.dispatch(action);

Reducer - mudando o estado

const reducer = (state, action) => {
    switch(action.type) {
        case "CREATE_TASK":
            return {
                ...state,
                tasks: [...state.tasks, action.data],
            }
        default:
            return state;
    }
};

Seletores - cache

const tasksSelector = state => state.tasks;
// a porcentagem só é recalculada
// quando o resultado de tasksSelector mudar
const percentageDoneSelector = createSelector(
    tasksSelector,
    tasks => {
        const doneTasksCount = tasks.filter(x => x.isDone).length;
        const tasksCount = tasks.length;
        return 100 * doneTasksCount / tasksCount;
    }
);

Efeitos colaterais

  • redux-thunk

  • redux-saga

  • redux-observable

MobX

Como funciona

  • Observáveis

  • Ações

  • Valores computados

  • Reações

    • Observadores

Observáveis, ações e valores computados

class TaskStore {
    @observable tasks = [];
    
    @computed get percentageDone() {
        const { tasks } = this;
        return tasks.filter(x => x.isDone).length / tasks.length;
    }

    @action createTask = (task) => {
        this.tasks.push(task);
    }
}

Redux ou Mobx?

Vantagens e desvantagens

Características em comum

  • Centraliza estado global em stores disponibilizadas pra componentes em qualquer lugar na árvore através de contexto;

  • Conceitos em comum: estado global, ações, valores com cache, efeitos colaterais...

Vantagens do Redux

  • Time travel debugging

  • Mais arquitetura do que biblioteca

    • Tudo explícito, sem mágicas

    • Mais fácil de raciocinar

  • A arquitetura força boas práticas

Desvantagens do Redux

  • MUITO boilerplate;

    • Pra cada feature: action, reducer, seletores...

  • Fluxo fragmentado, dividido em múltiplos arquivos;

  • Difícil de integrar com tipos estáticos (Typescript/Flow);

  • Cache, efeitos colaterais e otimizações não fazem parte da lib;

Vantagens do Mobx

  • Otimizações de performance automáticas

    • Semelhante a Redux com immutable.js e PureComponent

  • Store centralizada e legível

  • Efeitos colaterais e cache fazem parte da biblioteca

  • Integra muito bem com tipos estáticos

Desvantagens do Mobx

  • Muita "mágica"

  • Muito permissivo

    • É fácil de aderir a más práticas

    • Como saber se a propriedade que o componente recebeu é ou não observável?

E o campeão é...

Disclaimer #1

Você pode não precisar de uma biblioteca de gerenciamento de estado.

só use uma quando tiver o problema que ela resolve

Disclaimer #2

Nem todo estado é global

em geral, estado global é pra lógica de negócio

Disclaimer #3

Existem (muitas) outras opções

Exemplos

  • mobx-state-tree

  • unstated

  • freactal

  • reduxx

  • ReactObservableStore

  • ... ou a própria api de contexto do React!

Obrigado!