Ainda vale a pena aprender Redux? – vem ver nossa opinião e o motivo dela

Ainda vale a pena aprender Redux? – vem ver nossa opinião e o motivo dela
Lorena Garcia
Lorena Garcia

Compartilhe

Se você já trabalhou com React, você já passou pela situação de ter que enviar valores de componentes pais para filhos, ou talvez tenha percebido que um valor precisaria ser usado em mais de um lugar da sua aplicação, e no final, acabou com todos os estados declarados no seu App.js?

Esse é o chamado prop drilling, problema que culminou na criação do Redux e, posteriormente, do useContext do próprio React.

O Redux foi por muito tempo uma peça central na gestão de estado com React, mas com a evolução constante do React e o surgimento de novas ferramentas, pode surgir a dúvida: Será que ainda vale a pena aprender Redux? Não tá muito ultrapassado?.

Se essas perguntas já passaram pela sua cabeça, relaxa! Vamos explorar em conjunto e vou te explicar o que você precisa saber sobre o assunto.

Alerta de spoiler: o Redux não ficou parado no tempo, e a versão mais recente com o Redux Toolkit trouxe uma abordagem mais simples e menos verbosa.

Neste artigo vamos ver o que mudou no Redux ao longo dos anos e porque ele continua relevante hoje em dia.

E, claro, nada melhor do que aprender na prática criando uma aplicação com ele.

Bora lá?

Como criar uma to-do List com Redux Toolkit

A melhor maneira de entender porque o Redux ainda é uma boa escolha é vê-lo em ação. Vamos construir uma To-do List usando o Redux Toolkit, que é uma versão simplificada do Redux.

Esta aplicação vai mostrar como o gerenciamento de estado com o Redux ficou mais direto e acessível.

Gif do personagem bob esponja lendo uma lista de tarefas bem longa.

Definir o Slice

O primeiro passo para começar com Redux Toolkit é criar um slice, nele é onde vamos definir o estado inicial e as funções que vão modificar esse estado.

import { createSlice } from '@reduxjs/toolkit';

const todoSlice = createSlice({
    name: 'todos',
    initialState: [],
    reducers: {
        addTodo: (state, action) => {
            state.push({ id: Date.now(), text: action.payload, completed: false });
        },
        toggleTodo: (state, action) => {
            const todo = state.find(todo => todo.id === action.payload);
            if (todo) {
                todo.completed = !todo.completed;
            }
        },
        removeTodo: (state, action) => {
            return state.filter(todo => todo.id !== action.payload);
        },
    },
});

export const { addTodo, toggleTodo, removeTodo } = todoSlice.actions;

export default todoSlice.reducer;

Estamos utilizando a função createSlice que faz o gerenciamento das tarefas da nossa To-do List. Com esse código simplificamos a forma como lidamos com o estado, reunindo as ações e a lógica de atualização em um lugar só.

Um ponto interessante é que, no caso do reducer addTodo, usamos state.push. Se você já estudou um pouco sobre imutabilidade pode estar se perguntando: “Mas não estamos modificando o estado diretamente aqui?”

Na verdade, o Immer, que já vem embutido no Redux Toolkit, cuida disso pra gente.

Ele permite que a gente escreva o código como se estivesse alterando o estado diretamente, mas por baixo dos panos, ele garante que o estado continue imutável.

No caso do removeTodo, a função ´filter` já retorna um novo array, então a imutabilidade está garantida.

O slice tem um nome ('todos') que identifica o estado que estamos gerenciando e um estado inicial definido como um array vazio.

Dentro dele, definimos três reducers que controlam como o estado pode ser alterado:

  • addTodo: esse reducer adiciona uma nova tarefa ao nosso estado. Quando chamamos essa ação, ela insere um novo item no array de tarefas, que inclui um id único, o texto da tarefa e um status de "não completa".
  • toggleTodo: já esse reducer possibilita que a gente alterne o status de uma tarefa, mudando-a entre "completa" e "não completa". Ele faz isso localizando a tarefa pelo id e invertendo seu estado.
  • removeTodo: com este reducer, podemos remover uma tarefa da lista. Ao chamar essa ação, filtramos o array de tarefas e excluímos o item correspondente ao id fornecido.

Bacana demais, né?

Configurar a Store

Agora vamos para a store, é ela que centraliza todos os estados da aplicação. Com a API configureStore, você vai ver que essa etapa ficou bem mais simples.

Não precisamos mais nos preocupar em combinar reducers ou adicionar middlewares manualmente, o configureStore faz isso pra gente.

Ele já vem pronto para:

  • Combinar automaticamente os reducers da aplicação;
  • Adicionar o middleware thunk, que é útil para lidar com ações assíncronas;
  • Configurar o Redux DevTools, que é aquele plugin bacana do navegador para inspecionar seu estado.

Vamos criar nossa store com o configureStore?

import { configureStore } from '@reduxjs/toolkit';
import todoReducer from './features/todoSlice';

const store = configureStore({
    reducer: {
        todos: todoReducer,
    },
});

export default store;

Aqui, além de importar o configureStore, nós também importamos o todoReducer e dentro do configureStore passamos um objeto com o reducer, onde definimos que o estado das todos (nossas tarefas) será gerenciado pelo todoReducer.

Essa abordagem facilita demais o processo de criação da store, porque já configura automaticamente o middleware e o Redux DevTools, exigindo bem menos esforço da nossa parte.

Se você quiser conferir o projeto da To-do List completinho, dá uma conferida no repositório no GitHub.

Banner promocional da Alura, com um design futurista em tons de azul, apresentando o texto

De volta para o passado: como o Redux era antes

Gif dos personagens Harry e Hermione voltando no tempo.

Agora que você viu como o Redux Toolkit funciona, vale uma breve viagem no tempo.

Antes, usar Redux era um pouco mais complicado do que a gente gostaria. A ideia sempre foi boa: centralizar todo o estado da aplicação em um só lugar, disparar ações para avisar que algo mudou e usar reducers para atualizar o estado de forma imutável.

O problema é que, na prática, a gente acabava escrevendo muito mais código.

Lá no ínicio, para criar uma store, era preciso usar o createStore, combinar todos os reducers manualmente com o combineReducers e adicionar middlewares como o redux-thunk com o applyMiddleware.

E se quiséssemos usar o Redux DevTools, precisávamos habilitar o suporte manualmente.

E o processo de criar actions e reducers? Vamos combinar que não era dos mais simples.

Primeiro, a gente definia constantes para os tipos de ação, criava action creators para gerar os objetos de ação, e depois, o reducer tinha que saber exatamente como lidar com cada uma dessas ações. Tudo isso resultava em um código bem extenso.

Olha só como era adicionar uma tarefa (to-do) no Redux:

const ADD_TODO = 'ADD_TODO';
const TODO_TOGGLED = 'TODO_TOGGLED';

// Action creators
export const addTodo = (text) => ({
  type: ADD_TODO,
  payload: { text, id: nanoid() },
});

export const todoToggled = (id) => ({
  type: TODO_TOGGLED,
  payload: { id },
});

export const todosReducer = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO:
      return state.concat({
        id: action.payload.id,
        text: action.payload.text,
        completed: false,
      });
    case TODO_TOGGLED:
      return state.map((todo) => {
        if (todo.id !== action.payload.id) return todo;
        return { ...todo, completed: !todo.completed };
      });
    default:
      return state;
  }
};

Um bocado de código, né? O mais complicado era fazer as atualizações de estado de forma imutável - ou seja, sem alterar diretamente os objetos e arrays.

Isso acabava sendo feito manualmente com propagação de objetos (´…`) e operações em arrays, o que deixava o código propício a erros.

A evolução: Toolkit, Immer e Saga

Lembra que eu dei um spoiler lá no começo dizendo que o Redux não ficou parado no tempo? Pois é, ele foi se adaptando para atender às necessidades de desenvolvimento de aplicações mais elaboradas.

E não foi apenas o Toolkit que mudou o jogo - há mais de uma ferramenta envolvida nessa evolução, e uma delas é o Immer, que já mencionei antes.

A ideia de facilitar a imutabilidade do estado foi uma das grandes sacadas do Toolkit. E é o Immer que cuida disso de forma automática, possibilitando escrever código como se estivéssemos alterando o estado diretamente, sem as complicações que tínhamos antes.

Com ele, podemos fazer alterações em um rascunho temporário do estado, como se estivéssemos editando um documento e ao invés de nos preocuparmos em não alterar o estado original, nós interagimos com esse rascunho.

Depois que todas as mudanças estão feitas, o Immer produz o estado final, mantendo a imutabilidade.

É como ter um assistente que recebe a carta original e nos dá uma cópia para anotar as alterações e quando terminamos, o assistente entrega a versão finalizada, que é imutável.

Três blocos representando versões de um documento, lado a lado, com os rótulos Atual à esquerda, Rascunho no meio e Próximo à direita. Entre cada versão, há uma seta azul com o texto "immer", indicando a transformação de uma versão para outra.

Além do Immer, não podemos deixar de fora o Redux-Saga. Essa biblioteca foi projetada para facilitar o gerenciamento de efeitos colaterais nas aplicações, como requisições de dados ou interações com cache do navegador.

A ideia é que ele torne esses processos mais simples de administrar, com melhor desempenho na execução, e também facilitar testes e o tratamento de erros.

A grande sacada do Redux-Saga é o uso de Generators, uma funcionalidade do JavaScript que torna possível escrever funções que podem ser interrompidas e retomadas, facilitando a criação de fluxos assíncronos.

Essa característica viabiliza que a gente escreva fluxos assíncronos de forma clara e organizada. Funciona como um assistente que cuida de tarefas complexas sem bagunçar o que está acontecendo no restante da aplicação.

Apesar do Redux Toolkit já incluir o redux-thunk para lidar com promessas e ações assíncronas, o Redux-saga é uma boa alternativa caso você precise de mais flexibilidade no controle de fluxos.

Por que tudo isso é importante? Porque hoje o Redux-Toolkit oferece uma solução muito mais completa, que reduz drasticamente a complexidade e boilerplate (o código repetitivo necessário para configurar coisas simples) comparado ao que fazíamos no passado.

Essas melhorias tornam o Redux mais amigável para equipes de desenvolvimento, facilitando a testabilidade e a manutenção do código.

Conclusão: ainda vale a pena aprender redux?

Sim! Ainda vale a pena aprender Redux, especialmente agora com o Toolkit. Se você está lidando com um projeto onde o gerenciamento de estado se torna complexo ou precisa ser centralizado, o Redux continua sendo uma escolha confiável.

Ele se adaptou ao longo dos anos, oferecendo uma experiência mais amigável e menos verbosa, mantendo-se relevante em projetos grandes.

Claro, nem sempre o Redux será a opção ideal, em projetos menores, onde o gerenciamento de estado não é tão crítico, outras opções podem ser mais leves e adequadas.

Mas, quando o desafio envolve múltiplos estados e ações que precisam ser compartilhados entre diferentes partes da aplicação, o Redux, principalmente com o Toolkit, brilha.

No final das contas, a escolha vai depender das necessidades do seu projeto. Mas uma coisa é certa: o Redux evoluiu e está longe de ser ultrapassado!

Se você quiser mergulhar mais ainda nesse assunto, pode dar uma olhada na formação Gerencie estados em React com Redux, você vai aprender a usar o Redux Toolkit, trabalhar com middlewares e muito mais. Bora lá?

Referências

Lorena Garcia
Lorena Garcia

Lorena é formada em Análise e Desenvolvimento de Sistemas e, atualmente, faz parte do time de Suporte Educacional. Ama aprender coisas novas e dividir com outras pessoas. No tempo livre gosta de jogar games variados, ler livros e assistir animes.

Veja outros artigos sobre Front-end