Loading Light/Dark Toggle
 All publications

<h1>

Autenticación simple con React y Redux Toolkit 

</h1>

Updated on May 24, 2022 . 9 min read

<article>

En este artículo te voy a enseñar a utilizar Redux Toolkit en un proyecto React JS con Typescript y creado con Vite JS.

¿Por qué usar Vite JS?

Vite JS es una herramienta del frontend desarrollada por los creadores de Vue JS que permite crear aplicaciones de Javascript con algún framework o libreria como Vanila, ReactJs, Vuejs, Svelte (tanto en versión Javascript, como Typescript). Gracias a su característica de Instant Server Start (Inicio Instantáneo del servidor), a diferencia de create react app, Vite ejecuta la aplicación mucho más rápido y los cambios reflejados de manera instantánea.

Creación del proyecto

En mi caso usare el gestor de paquetes yarn pero si deseas lo puedes hacer con npm, puedes observar una guía detallada en la documentación oficial.

Creamos nuestra aplicación

yarn create vite

Este comando solicitará el nombre de tu proyecto, el framework con en que vas a trabajar (en nuestro caso react), y finalmente te preguntará si deseas usar Typescript.

Una vez que el proyecto se haya creado accedemos al direcotorio de la aplicación y ejecutamos el comando yarn o npm i para obtener todas las dependencias. En mi caso

cd simple-auth-app/ yarn

En este punto puede probar la correcta ejecución de tu aplicación, si estas usando yarn, con el siguiente comando:

yarn run dev

Nota la rapidez con la que se ejecutó tu aplicación!!

Dependencias necesarias

  • axios: Librería utilizada para hacer solicitudes HTTP
  • eslint-plugin-react-hooks: Nos ayuda a controlar errores y nos brinda ayuda cuando tengamos algún error de codificación de nuestros hooks.
  • redux: Gestor de estados de la aplicación.
  • sass: Permite usar SASS en lugar de simple CSS (si instalas esta extensión asegúrate de cambiar las extensiones de tus ficheros css a scss, además reemplaza la extensión importaciones en los ficheros App.tsx y main.tsx)
  • bootstrap: Framework de CSS
  • react-hook-form: Librería para el manejo y validación de formularios
  • react-router-dom: Gestor de rutas para React

Dependencias necesarias

yarn add axios @reduxjs/toolkit sass bootstrap react-hook-form react-router-dom @types/node react-redux

Dependencias de desarrollo

yarn add eslint-plugin-react-hooks --dev

Configuraciones generales

Como hemos instalado Boostrap en nuestro proyecto es necesario hacer las importaciones necesarias:

  • En el archivo App.scss importamos los stilos de Boostrap
@import 'node_modules/bootstrap/scss/bootstrap';
  • En el archivo main.tsx importamos el Javascript de Bootstrap (ya que estamos usando Boostrap 5, no es necesario Jquery)
  • En el mismo archivo también configuramos el Router de nuestra aplicación, esto nos permitirá manejar rutas.
import React from 'react'; import ReactDOM from 'react-dom'; import 'bootstrap/dist/js/bootstrap.bundle.min.js'; import { HashRouter } from 'react-router-dom'; import './index.scss'; import App from './App'; ReactDOM.render( <React.StrictMode> <HashRouter> <App /> </HashRouter> </React.StrictMode>, document.getElementById('root') );

Estructura de directorios

En mis proyectos suelo utilizar la siguiente estructura de directorios:

├── src/ ├── assets/ │ ├── images/ │ ├── icons/ │ ├── fonts/ │ ├── ... ├── components/ │ └── Component1.component.tsx ├── data/ ├── hooks/ ├── layout/ ├── models/ ├── pages/ │ └── page1/ │ ├── components/ │ └── Page1.page.tsx ├── redux/ │ ├── ... │ ├── store.tsx ├── routes/ │ ├── routes.tsx ├── services/ ├── utilities/ ... ├── App.scss ├── App.tsx ├── favicon.ico ├── index.scss └── main.tsx ...
  1. El directorio assets contiene todos los recursos multimedia como imágenes, fuentes, íconos, incluso aquí se pueden agregar archivos para la internacionalización de la aplicación en un directorio i18n.
  2. El directorio components contiene todos los componentes globales de tu aplicación por ejemplo: alertas personalziadas, laoders o componentes de paginación.
  3. El directorio data contiene constantes que puedes usar en tu aplicación, aquí puedes incluir rutas, o enumeraciones.
  4. El directorio hooks contiene hooks personalizados que ayudarán a abstraer lógica de tu aplicación.
  5. El directorio layout contiene los elementos principales por los que se conforma tu aplicación, por lo general suelen ser cuatro: Header, Sidebar, Footer y Skeleton.
  6. El directorio models contiene los modelos que usarás en tu aplicación ya que estamos usando Typescript, es importante mantener un correcto tipado en toda la aplicación.
  7. El directorio pages contiene las páginas por las que esta conformada tu aplicación, yo acostumbro a crear un direcotrio por cada conjunto de páginas (por ejemplo el directorio users contendrá las páginas: UsersList.page.tsx, UsersCreate.page.tsx y UserDetails.page.tsx) además puedes crear un subdirectorio componentes en caso de que todas estas páginas compartan componentes.
  8. El directorio redux contiene la configuración del estado global de neustra aplicaicón, esto lo veremos más adelante.
  9. El directorio routes contiene un archivo con la definición de las rutas de tu aplicación.
  10. El directorio services contiene la definición de axios para las peticiones HTTP, aquí puedes crear interceptores que te ayuden a agregar cabeceras o manejar los errores de mejor manera.
  11. Finalmente, el directorio utilities lo puedes usar para alamcenar funciones globales en tu aplicación por ejemplo: una función de conversión de divisas, un formateador de fechas, etc.

Autenticación simple usando Redux Toolkit

Para nuestro ejemplo vamos a crear dos páginas sencillas:

  • src/pages/home/Home.page.tsx: Esta será la página principal de la aplicación que estará protegida por un inicio de sesión previo.
const HomePage = (): JSX.Element => { return <>HomePage</>; }; export default HomePage;
  • src/pages/auth/Login.page.tsx: Esta será la página de inicio de sesión para nuestra aplicación.
const LoginPage = (): JSX.Element => { return <>LoginPage</>; }; export default LoginPage;

Además, creamos nuestros componentes del Layout, vamos a crear los siguientes componentes:

  • src/components/header.layout.tsx
  • src/components/footer.layout.tsx
  • src/components/skeleton.layout.tsx
import { ReactChild, ReactChildren } from 'react'; import Header from './header.layout'; import Footer from './footer.layout'; interface Props { children: ReactChild | ReactChild[] | ReactChildren | ReactChildren[]; } const Skeleton = ({ children }: Props): JSX.Element => { return ( <> <Header /> <main>{children}</main> <Footer /> </> ); }; export default Skeleton;

Tenemos que definir las rutas de nuestra aplicación, en nuestro caso solo tenemos la ruta / que conduce a la página principal, pero tu debes agregar todas las rutas de tu aplicación.

  • src/routes/app.routes.tsx
import { Navigate, Route, Routes } from 'react-router-dom'; import Skeleton from '../layout/skeleton.layout'; import HomePage from '../pages/home/Home.page'; const AppRoutes = (): JSX.Element => { return ( <Skeleton> <Routes> <Route path="/" element={<HomePage />} /> {/* Redirect to route */} <Route path="*" element={<Navigate replace to="/" />} /> </Routes> </Skeleton> ); }; export default AppRoutes;

Ahora, debemos definir las rutas principales en el fichero src/App.tsx, indicamos que si la ruta es cualquier otra que no sea login redireccionaremos al usuario a las rutas protegidas con un inicio de sesión. En este punto puedes agregar todas las rutas públicas de tu aplicación.

import { Route, Routes } from 'react-router-dom'; import './App.scss'; // pages import LoginPage from './pages/auth/Login.page'; import AppRoutes from './routes/app.routes'; function App(): JSX.Element { return ( <Routes> <Route path="/login" element={<LoginPage />} /> <Route path="*" element={<AppRoutes />} /> </Routes> ); } export default App;

Ya que vamos a usar redux en nuestra aplicación es importante definir el Provider con el estado global de la aplicaición, esto lo realizamos en el fichero src/main.tsx

import React from "react"; import ReactDOM from "react-dom/client"; import "bootstrap/dist/js/bootstrap.bundle.min.js"; import { HashRouter } from "react-router-dom"; import App from "./App"; import "./index.scss"; import { Provider } from "react-redux"; import store from "./redux/store"; ReactDOM.createRoot(document.getElementById("root")!).render( <Provider store={store}> <React.StrictMode> <HashRouter> <App /> </HashRouter> </React.StrictMode> </Provider> );

Empezaremos configurando redux para nuestra aplicación. Toda la configuración que veràs a continuación se basa en la documentación oficial de redx toolkit, piedes verla aquí.

Definimos del archivo src/redux/store.tsx, este archivo contiene la definición del estado de nuestra aplicación. Inicialmente contendrá:

import { configureStore } from '@reduxjs/toolkit'; const store = configureStore({ reducer: {}, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: false }) }); export default store; // Infer the `RootState` and `AppDispatch` types from the store itself export type RootState = ReturnType<typeof store.getState>; export type AppDispatch = typeof store.dispatch;

Aquí definimeros todos los reducers que forman parte del estado global de la aplicación.

Para el manejo de la autenticaciòn, suelo crear un directorio src/redux/auth. Además, definimos una interfaz para el manejo del estado, por lo regular suelo agregar una variable booleana que indicará si la petición HTTP está siendo realizada o si ya finalizó, y una variable de error en el caso de que exista un error durante la petición.

export interface AuthState { isLoading: boolean; error?: any; userInfo: Auth | undefined; }

A partir de esta interfaz defino el estado inicial para la autenticación.

const initialState: AuthState = { isLoading: false, userInfo: getUserFromLocalStorage() };

Para la autenticación estoy usando el LocalStorage (puedes revisar la función getUserFromLocalStorage() en el repositorio de Github). Posteriormente definimos el authenticationSlice donde se definen los diferentes estados que puede tener la aplicación, además se indica el estado inicial.

** Recuerda que todo esto se basa en la documentación oficial de Redux Tookit.

export const authenticationSlice = createSlice({ name: 'authentication', initialState, reducers: { request: (state): AuthState => { return { ...state, isLoading: true }; }, success: (state, action: PayloadAction<any>): AuthState => { return { ...state, isLoading: false, userInfo: action.payload }; }, fail: (state, action: PayloadAction<any>): AuthState => { return { ...state, isLoading: false, error: action.payload }; }, logout: (state): AuthState => { return { ...state, isLoading: false, userInfo: undefined }; } } });

Posteriormente definimos las funciones de authLogin y authLogout que harán uso de los diferentes estados que hemos definido anteriormente.

Una vez definido el estado de la autenticación en el archivo auth.slice.tsx inyectamos su reducer en el store global de la aplicación (src/redux/store.tsx), el resultado final es el siguiente:

import { configureStore } from '@reduxjs/toolkit'; import { authenticationReducer } from './auth/auth.slice'; const store = configureStore({ reducer: { authentication: authenticationReducer }, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: false }) }); export default store; // Infer the `RootState` and `AppDispatch` types from the store itself export type RootState = ReturnType<typeof store.getState>; export type AppDispatch = typeof store.dispatch;

Una vez configurado el store de la aplicaicón podemos pasar al diseño y funcionalidad de nuestras páginas.

Para el inicio de sesión he creado un simple formulario usando componentes de Boostrap y react-hook-form. Además he hecho uso de las funciones de inicio de sesión definidas en src/redux/auth/auth.slice.tsx:

El uso de hooks como el useEffect es importante, si aún desconoces el funcionamiento de este hook te recomiendo leer sobre este Hook aquí.

Importante: Como se trata una aplicación sencilla de demostraciòn podrás usar cualquier email o contraseña cuando pruebes la aplicación.

Para nuestra página de Home simplemente definimos un título de la página y un botón para finalizar sesión.

Si tienes alguna duda en cuanto al menejo de las rutas, pudes revisar los archivos src/App.tsx y src/routes/app.routes.tsx. Para resumirlo, las rutas públicas como el login se definen en src/App.tsx mientras que las rutas privadas o que necesitas una autenticación previa se definene en src/routes/app.routes.tsx.

Recuerda que para esta demo app estamos usando el localstorage para mantener la sesión del usuario, las funciones encargadas del manejo del localstorage se encuentran en src/services/persistUser.service.tsx.

Comprobación

En este punto podemos verificar que la aplicación funcione correctamente.

React simple auth

Puedes encontrar el código completo de esta aplicación en mi repositorio de github recuerda que antes debes tener todo configurado (yarn y node instalados) para que funcione correctamente.

Código fuente de este proyecto https://github.com/baguilar6174/react-simple-auth-app


You can find this and other posts on my Medium profile some of my projects on my Github or on my LinkedIn profile.

¡Thank you for reading this article!

If you want to ask me any questions, don't hesitate! My inbox will always be open. Whether you have a question or just want to say hello, I will do my best to answer you!

</article>