2023-04-24

Redux y Redux Toolkit: Gestión del estado en una aplicación React

Redux es una biblioteca que se utiliza para gestionar el estado de una aplicación, facilitando la administración de un estado global a través de un almacenamiento centralizado. Se recomienda utilizar Redux cuando se necesita acceder a la información en toda la aplicación. Si la información solo se necesita en una página, se puede utilizar Context. Y si la información es necesaria entre componentes, se puede utilizar RxJS.

Descargas e instalación

npm install redux react-redux
npm install @reduxjs/toolkit

Estructura de carpetas

Es recomendable seguir una estructura de carpetas organizada para el uso de Redux. A continuación, se muestra una posible disposición de las carpetas en el proyecto:

  • 📂 src
    • 📂 models
      • 📄 user.ts
    • 📂 redux
      • 📄 store.ts
      • 📂 states
        • 📄 user-slice.ts

Implementación

A continuación, se presentará un ejemplo paso a paso de cómo utilizar Redux y Redux Toolkit en una aplicación React.

En el archivo store.ts dentro de la carpeta redux, configuramos el almacenamiento de Redux utilizando configureStore de Redux Toolkit. Definimos el estado inicial y los reducers necesarios para el manejo del estado. Por ejemplo:

import { User } from '@/models'
import { configureStore } from '@reduxjs/toolkit'
import { userSlice } from './states'

export interface AppStore {
	usuario: User
}

export default configureStore<AppStore>({
	reducer: {
		usuario: userSlice.reducer,
	},
})

En el componente raíz de la aplicación, importamos el proveedor Provider de react-redux y envolvemos la aplicación con el proveedor. Pasamos el almacenamiento store como prop al proveedor. Por ejemplo:

import { Provider } from 'react-redux'
import store from './redux/store'

function App() {
	return (
		<Provider store={store}>
			<Aplication />
		</Provider>
	)
}

Este va a ser nuestro slice sin persistencia y despues te voy a mostrar uno con localStorage

import { User } from '@/models'
import { createSlice, current } from '@reduxjs/toolkit'

const InitialState : User = {
  name: ''
  email: ''
}

export const userSlice = createSlice({
  name:'user'
  initialState: initalState,
  reducers: {
    // estas son funciones que luego podremos usar
    // state: estado actual (como el state del userState)
    // action.payload: info que nos mandan
    addUser : (state, action) => {
      // lo que retornamos reemplaza el estado actual
      return action.payload
    }
    resetUser: () => {
      // devolvemos initialState asi queda vacio el user
      return initalState
    }
    // Vamos a dejar por aca, podes agregar la cantidad que quieras
  }
})

export const { addUser, resetUser } = userSlice.actions

Ahora, con persistencia en localStorage, esto se puede cambiar a una base de datos

import { User } from '@/models'
import { createSlice, current } from '@reduxjs/toolkit'

const InitialState : User = {
  name: ''
  email: ''
}

export const userSlice = createSlice({
  name:'user'
  // Este operador ternario establece el estado de la siguiente manera:
  // verifica si hay un usuario en el localStorage y lo guarda en el estado.
  // Si no hay un usuario, entonces guarda el initialState.
  initialState: localStorage.getItem('user') ?
  JSON.parse(localStorage.getItem('user') as string)
  : initialState,
  reducers: {
    addUser : (state, action) => {
      localStorage.setItem('user', JSON.stringify(action.payload))
      return action.payload
    }
    resetUser: () => {
      localStorage.removeItem('user');
      return initalState
    }
  }
})

export const { addUser, resetUser } = userSlice.actions

Solo queda como consumir lo que acabamos de hacer

import { useDispatch, useSelector } from 'react-redux'
import { addUser, resetUser, AppStore } from '@/redux'

export const home = () => {
  // en el userState vamos a tener guardado el estado
  const userState = useSelector((store:AppStore) => store.usuario)
  // y para usar las funciones usamos dispatch
  const dispatch = useDispatch()

  const resetUser = () => {
    dispatch(resetUser())
  }

  const addUser = () => {
    dispatch(addUser({ name:'jero', email:'jero@gmail.com' }))
  }
  const
  return(
    <>
      <ul>
        <li>Name: {userState.name}</li>
        <li>Email: {userState.email}</li>
      </ul>
      <div>
        <button onClick={addUser}>Add user</button>
        <button onClick={resetUser}>Reset user</button>
      </div>
    </>
  )
}

En este ejemplo, utilizamos useSelector para acceder al estado del usuario y useDispatch para despachar las acciones addUser y resetUser. Podemos mostrar la información del usuario y utilizar los botones para agregar un usuario o restablecer el usuario.

Con esto, hemos implementado Redux y Redux Toolkit en una aplicación React. Redux nos permite gestionar el estado de forma centralizada, facilitando el acceso a la información en toda la aplicación y mejorando la escalabilidad y mantenibilidad del código.