DEV Community

Cover image for Introducci贸n react-redux y redux toolkit
leobar37
leobar37

Posted on

Introducci贸n react-redux y redux toolkit

Despu茅s de haber entendido algunos conceptos de Redux, lleg贸 el momento de utilizarlo como tal 馃榿.

Setup

Para hacer el setup de la app usar茅 vite. Vite es una alternativa a webpack, el cual mejora la experiencia de usuario y es mucho m谩s r谩pido. Si quieres saber m谩s acerca de los beneficios de vite, puedes visitar el siguiente art铆culo

Para crear una aplicaci贸n con vite y react, solo es necesario abrir tu consola y poner el siguiente comando.

yarn create vite redux-tutorial --template react-ts

Enter fullscreen mode Exit fullscreen mode

La opci贸n de --template le dice a vite con que template inicializar el proyecto, en este caso el de react-ts ahora ya se tendr谩 la siguiente estructura.

file structure

Ahora empecemos con las dependencias, como hab铆amos dicho utilizaremos redux con react, para eso tenemos que instalar el paquete react-redux, el cual trae lo necesario para hacer la conexi贸n a redux, adem谩s a ellos vamos a instalar @reduxjs/toolkit el cual trae algunos superpoderes para redux

yarn add react-redux @reduxjs/toolkit
Enter fullscreen mode Exit fullscreen mode

驴Que es redux toolkit?

Redux esta bien, pero era un poco complicado. Actualmente, contamos con Redux toolkit 茅l ofrece las siguientes soluciones:

  • Simplifica la configuraci贸n de redux
  • Elimina la necesidad de agregar m煤ltiples paquetes para tener una aplicaci贸n escalable.
  • Reduce el c贸digo repetitivo.

Actualmente no se recomienda usar react-redux sin @reduxjs/toolkit.

Preparando el Store

Para empezar a escribir l贸gica con redux, lo primero que se tiene que hacer es configurar el Store. Para eso Redux toolkit provee un m茅todo que nos ayuda con el procedimiendo, el cual se llama configureStore.

// store/index.ts

import { configureStore } from "@reduxjs/toolkit";

export const store = configureStore({
  reducer: {},
  devTools: process.env.NODE_ENV !== "production",
});

export default store;

Enter fullscreen mode Exit fullscreen mode

configureStore

Ahora ya tenemos 茅l store :) . Al hacer esto redux-toolkit ha puesto algunas configuracioens por defecto, las cuales ir茅 comentando conforme avancemos en el ejemplo. En este instante podemos hablar de las devTools las cuales son indispensables para poder depurar la aplicaci贸n. En este caso la opci贸n devtools se activa solo en producci贸n, tambi茅n puedes personalizar el funcionamiento, pasando un objeto de opciones.

Conexi贸n con React

Ahora es momento de poner disponible el store hacia React, para eso react-redux provee un Provider para poner disponible el Store en todo el 谩rbol de componentes.

import "./App.css";
import { Provider as ReduxProvider } from "react-redux";
import store from "./store";

function App() {
  return (
    <ReduxProvider store={store}>
      <div></div>
    </ReduxProvider>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

Estructura de archivos en Redux

Ahora que ya se tiene la tienda en el nivel superior de la aplicaci贸n, es hora la l贸gica de nuestra aplicaci贸n, en este caso vamos a hacer una agenda de contactos, para poder realizar un CRUD. Antes de continuar necesitamos tener en cuenta algo muy importante, el cual es la estructura de los archivos. Si bien React es una librer铆a muy flexible frente a la estructura de archivos, Redux poner a nuestra disposici贸n una estructura base, para a partir de eso organizar nuestros archivos.

Pensando en Ducks

Ducks es una propuesta que b谩sicamente propone que empaquetemos un conjunto de acciones, reductores, nombres de acciones a una funcionalidad en concreto, llamando a esta agrupaci贸n duck el cual, tranquilamente, puede empaquetarse y distribuirse como una librer铆a.

Ahora, teniendo un poco en cuenta los patos 馃槄, vamos a dividir la aplicaci贸n en algo parecido, pero le llamaremos features. De esta manera.

Modules

Feature Structure:

Como se mencionaba en un inicio, el ecosistema de React es muy flexible a la hora de organizar los archivos. Teniendo en cuenta los elementos de redux, al momento de partir una feature debemos dividir actions, reducer, selectors esto mejora la organizaci贸n.

En mi caso inspirado un poco en el siguiente art铆culo, mi estructura es la siguiente.

modules

View: Carpeta donde van las vistas que el usuario va a ver en pantalla, generalmente todos los componentes que son utilizando junto con el router de la aplicaci贸n. Por ejemplo, si estamos creando una aplicaci贸n de inventarios, el listado de estos productos podr铆an ir en una pantalla producs/list.

Componentes: Normalmente, se querr谩 tener una carpeta components en general, donde est茅n ubicados todos aquellos componentes, que pueden ser usados en cualquier lugar, una feature puede tener componentes que sean propios de la caracter铆stica, por ejemplo el listado, de productos.

actions: En esta carpeta ir谩n todas las acciones ligadas a esta caracter铆stica.

reducer: Cada feature tiene como regla que debe exportar un solo reductor, eso no quiere decir que solo tengamos que concentrar toda l贸gica en un solo reducer, podemos usar combineReducers para combinar m煤ltiples reducer en unos solo si es que fuese necesario.

Puedes pensar en una feature como una mini aplicaci贸n dentro de una aplicaci贸n, este se encarga de un proceso en concreto, que al final aportar谩 un valor agregado a la aplicaci贸n en general.

Accciones

Las acciones son objetos planos que expresan una intenci贸n de cambiar el estado, eso es lo que se mencion贸 en el art铆culo anterior. Puedes pensar en una acci贸n como un evento ocurrido en la aplicaci贸n, por ejemplo; se agreg贸 un producto, se elimin贸 un contacto, cargando contactos, todos ellos describen algo que est谩 pasando en al app.

Dicho esto podemos empezar a escribir acciones, las acciones tiene un est谩ndar que indican que deben ser as铆.

{
  type: 'ADD_TODO',
  payload: {
    text: 'Do something.'
  }
}
Enter fullscreen mode Exit fullscreen mode

Creadores de acciones:

Normalmente, las acciones puede despacharse de la siguiente manera.

store.dispatch({ type: "ITEM_ADDED_TO_CART", payload: 47 });
Enter fullscreen mode Exit fullscreen mode

Pero en cierto punto, poner el tipo, cada vez que queramos despachar esta acci贸n, no es muy escalable porque si se quisiera cambiar el tipo de acci贸n, tendr铆a que hacerlo en diferentes archivos y adem谩s, se vuelve complicado repetir lo mismo.

Ah铆 es donde entran loas creadores de acciones, que no son nada m谩s que funciones encargadas de crear este objeto, un creador de acci贸n ser铆a el siguiente.

function doAddToDoItem(text) {
  return { type: "TODO_ADDED", payload: text };
}
Enter fullscreen mode Exit fullscreen mode

Entonces, cada vez que se requiera formar esta acci贸n, solo es necesario ejecutar doAddToDoItem.

Redux toolkit Simplifica este procedimiento con un utility llamado createAction el cual es una HOF(higher order function) los cuales son funciones que retornan funciones.

// features/schedule/actions/schedule.actions.ts
import { createAction } from "@reduxjs/toolkit";

export const contactAdded = createAction("CONTACT_ADDED");
Enter fullscreen mode Exit fullscreen mode

Ahora contactAdded es una funci贸n que al ser disparada crear谩 una acci贸n de tipo CONTACT_ADDED es importante saber que por recomendaci贸n de redux las acciones deben ser "Descripciones de eventos que ocurrieron" en lugar expresarlas en presente, como por ejemplo ADD_CONTACT.

Payload:

Hasta este paso se cre贸 la acci贸n contactAdded, pero esto no es suficiente para agregar un contacto, se necesitar铆a la informaci贸n de ese contacto. En el caso de typescript redux toolkit tiene un gen茅rico para poder describir el payload.

import { createAction } from "@reduxjs/toolkit";

export const contactAdded =
  createAction<{ name: string; phone: string }>("CONTACT_ADDED");
Enter fullscreen mode Exit fullscreen mode

Listo ahora el primer par谩metro(payload) de contactAdded estar谩 tipado.

Reducer

Como se mencion贸 anteriormente, los reducers son funciones puras que toman el estado actual y la acci贸n para retornar un nuevo estado.

Redux toolkit exporta una funci贸n llamada createReducer la cual facilita la creaci贸n de un reducer agregando ciertas caracter铆sticas que facilitan el desarrollo.

import { createReducer } from "@reduxjs/toolkit";

const initalState = {
  contacts: [],
};

export type ScheduleState = typeof initalState;

const reducer = createReducer(initalState, (builder) => {});
Enter fullscreen mode Exit fullscreen mode

Esta ser铆a la forma de crear un reducer con Redux toolkit

Case:

Anteriormente vimos, que cuando creamos un reducer dentro de el planteamos un switch...case para manejar cada acci贸n.

const reducer = (state, action) => {
  switch (action) {
    case "EAT": {
      return {
        ...state,
        eatCount: state.eatCount + 1,
      };
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

Redux toolkit propone una forma m谩s amigable de hacerlo, mediante un objeto builder, el cual expone una serie de m茅todos como addCase con el cual le recibe como par谩metros.

ActionCreator: La funci贸n generada por createActiono una acci贸n como tal.

Reducer: El reducer encargado solo de manejar esta acci贸n.

Incorporando la l贸gica de agregar contacto, tendr铆amos lo siguiente.

import { createReducer } from "@reduxjs/toolkit";
import * as scheduleActions from "../actions/schedule.actions";

export interface IContact {
  id: number;
  name: string;
  phone: string;
}
const initalState = {
  contacts: [] as IContact[],
};

export type ScheduleState = typeof initalState;

const reducer = createReducer(initalState, (builder) => {
  builder.addCase(scheduleActions.contactAdded, (state, action) => {
    state.contacts.push({
      id: state.contacts.length,
      name: action.payload.name,
      phone: action.payload.phone,
    });
  });
});
Enter fullscreen mode Exit fullscreen mode

Si eres curioso. La manera en como builder encadena todos los casos sigue fluent Style馃樁 .

Hay algo notable aqu铆, y es que al parecer no estamos siguiendo el primer principio de Redux, que dice que el estado es de solo lectura, ose es inmutable. Bueno podemos ahorrarnos esa preocupaci贸n con Immer, el cual explicar茅 en el siguiente parte :).

Happy Coding馃槃

Discussion (0)