Post Top Ad

Your Ad Spot

jueves, 15 de octubre de 2020

React, Axios y Redux: obtenga y guarde datos de forma asincrónica en el almacenamiento local

 En este tutorial, aprenderemos sobre muchos de los conceptos de Redux creando una aplicación React simple desde cero usando React, Redux y Axios para buscar y guardar datos de forma asincrónica en el almacenamiento local.

La aplicación que crearemos es una aplicación de jerga JavaScript simple que se basa en la jerga JavaScript simplificada disponible en este repositorio . Exportaremos las entradas como datos JSON y las consumiremos desde nuestra aplicación React usando Axios . El estado será manejado por Redux.

Para nuestra aplicación de demostración, creamos una API JSON generada estáticamente a partir del repositorio GitHub de jerga de JavaScript simplificado .

Nota: Si está consumiendo cualquier otro recurso, asegúrese de tener CORS habilitado para que el navegador no impida la lectura del recurso remoto debido a la Política del mismo origen .

La aplicación también incluirá una página de favoritos donde puede agregar y eliminar sus términos JS favoritos de la jerga.

Estos son los pasos de nuestro tutorial:

  • Paso 1: instalación de la aplicación Create-React e inicialización de una aplicación React
  • Paso 2: instalación de Axios, Redux, React-redux y Redux-thunk
  • Paso 3: creación de acciones de Redux
  • Paso 4: creación de reductores Redux
  • Paso 5: creación de la tienda Redux
  • Paso 6: creación del componente React
  • Paso 7: guardar datos en el almacenamiento local

Introducción

Redux es una implementación del patrón Flux : una arquitectura de aplicación para construir interfaces de usuario que son creadas y utilizadas por Facebook.

Redux es una biblioteca para administrar el estado de su aplicación que generalmente se usa con React, pero también se puede usar con otras bibliotecas y marcos. Funciona utilizando un almacén de estado global común entre todos los componentes de la aplicación.

¿Por qué usar Redux?

Redux es una buena solución para aplicaciones medianas y grandes que puede ayudarlo a manejar requisitos complejos de administración de estado. Pero no es necesario en todos los casos de uso.

Por ejemplo, si tiene componentes con muchos hijos y desea pasar el estado al árbol de hijos, puede usar la API React Context para acceder al estado en cualquier componente en cualquier nivel sin pasar el estado a los componentes que en realidad no lo necesitan solo porque lo necesita un componente secundario.

Para obtener más información, lea Es posible que no necesite Redux por Dan Abramov, el creador de Redux.

Prerrequisitos

Necesitaremos algunos requisitos previos para este tutorial, como:

  • Una versión reciente de Node.js y NPM instalada en su sistema,
  • Conocimiento de los conceptos esenciales de JavaScript y React modernos,

Si tiene los requisitos previos anteriores, comencemos con el primer paso donde instalaremos la create-react-apputilidad y crearemos una aplicación React.

Paso 1: instalación de la aplicación Create-React e inicialización de una aplicación React

En este paso, instalaremos la create-react-apputilidad, a continuación procederemos a inicializar nuestro proyecto React.

Abra una nueva terminal y ejecute el siguiente comando:

$ npm install -g create-react-app

Nota: Es posible que deba agregar sudoantes de su comando en Linux y macOS o usar una CMD con acceso de administrador si desea instalar paquetes globalmente en su sistema. También puede simplemente arreglar sus permisos npm .

En el momento de escribir este artículo, create-react-app v3.1.1 está instalado.

Ahora, estamos listos para crear nuestro proyecto React. Regrese a su terminal y ejecute el siguiente comando:

$ cd ~
$ create-react-app javascriptjargon

A continuación, navegue dentro de la carpeta de su proyecto y ejecute el siguiente comando para iniciar el servidor de desarrollo local:

$ cd ~/javascriptjargon
$ npm start

Su aplicación estará disponible en la http://localhost:3000dirección.

En el siguiente paso, instalaremos Axios, Redux react-reduxredux-thunk.

Paso 2: instalación de Axios, Redux, React-redux y Redux-thunk

En el paso anterior, creamos nuestro proyecto React y lo servimos localmente. En este paso, instalaremos Axios, Redux, sus enlaces React y también redux-thunk.

Abra una nueva terminal, navegue dentro de la carpeta de su proyecto y ejecute el siguiente comando:

$ npm install --save redux react-redux redux-thunk

Redux-thunk es un middleware que extiende Redux para permitirle escribir lógica asincrónica que interactúa con la tienda. Por ejemplo, para obtener datos de recursos remotos.

A continuación, también necesitamos instalar Axios:

$ npm install axios --save

Paso 3: creación de acciones de React Redux

Según los documentos oficiales:

Las acciones son cargas útiles de información que envían datos desde su aplicación a su tienda. Son la única fuente de información de la tienda. Los envía a la tienda usando store.dispatch () .

Las acciones son objetos simples de JavaScript que deben tener una typepropiedad que indique el tipo de acción que se está realizando. Por ejemplo, en nuestro caso, podemos crear una acción de tipo ADD_FAVORITE_TERM:

{ 
 type: 'ADD_FAVORITE_TERM'
}

En la mayoría de los casos, una acción también puede incluir datos:

{ 
 type:'ADD_FAVORITE_TERM', 
 name: 'Ajax'
}

En este ejemplo, el nombre del evento es ADD_FAVORITE_TERMy los datos son el nombre.

Dentro de la srccarpeta, cree una carpeta llamada actions:

$ cd src
$ mkdir actions

A continuación, navegue dentro de la actionscarpeta y cree un types.jsarchivo:

$ cd actions
$ touch types.js

Abra el types.jsarchivo con su editor de código preferido (usaremos el editor nano):

$ nano types.js

A continuación, agregue las siguientes constantes y guarde el archivo:

[~/javascriptjargon/src/actions/types.js]

export const ADD_FAVORITE_TERM = 'ADD_FAVORITE_TERM';
export const REMOVE_FAVORITE_TERM = 'REMOVE_FAVORITE_TERM';
export const ADD_FETCHED_DATA = 'ADD_FETCHED_DATA';

A continuación, cree un index.jsarchivo dentro de la actionscarpeta:

$ touch index.js

Abra el archivo usando su editor de código:

$ nano index.js

A continuación, comience agregando el siguiente código al index.jsarchivo:

[~/javascriptjargon/src/actions/index.js]

import { ADD_FETCHED_DATA, ADD_FAVORITE_TERM, REMOVE_FAVORITE_TERM } from './types.js';
import axios from 'axios';
const apiUrl = 'https://www.techiediaries.com/api/data.json';

Nos importan nuestros ADD_FETCHED_DATAADD_FAVORITE_TERMREMOVE_FAVORITE_TERMlos tipos de acciones que hemos definido anteriormente en el actions/types.jsarchivo. También importamos el axioscliente y definimos la apiUrlvariable constante que contiene la URL de nuestra API JSON.

A continuación, en el mismo actions/index.jsarchivo defina los dos métodos siguientes:

[~/javascriptjargon/src/actions/index.js]

export const addFavoriteTerm =  (data) => {
    return {
      type: ADD_FAVORITE_TERM,
      payload: {
        name: data.name,
        description: data.description
      }
    }
};

export const removeFavoriteTerm = name => {
    return {
      type: REMOVE_FAVORITE_TERM,
      payload: {
        name
      }
    }
}

Estos dos métodos se denominan creadores de acciones,

Los creadores de acciones son simplemente funciones que crean y devuelven acciones.

Primero definimos la addFavoriteTerm()función que crea y devuelve una acción del ADD_FAVORITE_TERMtipo y proporciona a la acción una carga útil de datos compuesta por el nombre y la descripción, pasados ​​como argumento a la función, del término JS que los usuarios están agregando a sus favoritos.

A continuación, definimos la removeFavoriteTerm()función que crea y devuelve una acción del REMOVE_FAVORITE_TERMtipo y namecarga útil que se refiere al nombre del término JS que los usuarios quieren eliminar de sus favoritos.

Ahora, necesitamos definir una función que obtenga datos de la API JSON y envíe una acción del ADD_FETCHED_DATAtipo con los datos obtenidos como carga útil de la siguiente manera:

[~/javascriptjargon/src/actions/index.js]

export const fetchData = () => {
    return (dispatch) => {
        return axios.get(apiUrl)
            .then(response => {
                return response.data
            })
            .then(data => {
                dispatch({
                    type: ADD_FETCHED_DATA,
                    payload: data
                })
            })
            .catch(error => {
                throw (error);
            });
    };
};

Observe que esta función es diferente de las funciones anteriores (creadores de acciones) porque realiza una operación asincrónica y devuelve una función, en lugar de un objeto, que tiene un dispatchargumento pasado .

Esta función se denomina creador de acciones de procesador .

Según Wikipedia :

Un procesador es una subrutina que se utiliza para inyectar un cálculo adicional en otra subrutina. Los procesadores se utilizan principalmente para retrasar un cálculo hasta que se necesite su resultado, o para insertar operaciones al principio o al final de la otra subrutina. Tienen una variedad de otras aplicaciones en la generación de código de compilador y programación modular.

En el fetchData()procesador, primero devolvemos una función que toma un argumento de despacho. En el cuerpo de la función devuelta llamamos al get()método del cliente axios para enviar una solicitud GET a nuestro punto final JSON. Axios devuelve una Promesa de JavaScript que se resuelve con los datos obtenidos o se rechaza con un error.

Si la Promesa se resuelve con éxito, enviamos una acción del ADD_FETCHED_DATAtipo, junto con los datos extraídos de la API como carga útil, a la tienda utilizando el dipatch()método pasado .

Un creador de acciones puede devolver una función en lugar de un objeto de acción gracias al middleware Redux Thunk que proviene del paquete redux-thunk que instalamos previamente y que agregaremos más adelante a nuestra tienda Redux.

Enviar una acción es simplemente enviar la acción a la tienda Redux. Normalmente, enviamos acciones desde la interfaz de usuario después de las reacciones de los usuarios. En el caso de operaciones asincrónicas como solicitudes de red, también podemos enviar acciones de creadores de acciones.

Eso es todo lo que necesitamos para definir nuestras acciones. En el siguiente paso, veremos cómo usar reductores para cambiar el estado de la aplicación después de enviar acciones.

Paso 4: creación de reductores React Redux

En este paso, veremos qué es una función reductora y agregaremos reductores a nuestra aplicación.

Los reductores son funciones de JavaScript puras que se utilizan para establecer y actualizar el estado de la aplicación en respuesta a las acciones enviadas a la tienda.

Antes de escribir los reductores, es esencial pensar en la forma del estado de su aplicación.

Redux almacena todo el estado como un único objeto JavaScript, por lo que necesitará conocer los atributos de ese objeto para poder escribir los reductores necesarios. En nuestro caso, necesitamos almacenar lo siguiente:

  • La matriz de términos de JavaScript obtenidos de la API JSON,
  • La matriz de términos de JavaScript favoritos que el usuario ha marcado como favorito durante el uso de la aplicación.

Regrese a su terminal y, dentro de la src/carpeta, cree una reducerscarpeta y navegue hasta ella usando los siguientes comandos:

$ cd ..
$ mkdir reducers
$ cd reducers

A continuación, cree los archivos index.jstermsReducer.jsfavoritesReducer.jsutilizando los siguientes comandos:

$ touch index.js
$ touch termsReducer.js
$ touch favoritesReducer.js

Abra el reducers/termsReducer.jsarchivo:

$ cd ..
$ nano reducers/termsReducer.js

A continuación, agregue el siguiente código:

[~/javascriptjargon/src/reducers/termsReducer.js]

import { ADD_FETCHED_DATA } from '../actions/types';

export default function termsReducer(state = [], action) {
    switch (action.type) {

        case ADD_FETCHED_DATA:
            return [ ...action.payload];
        default:
            return state;
    }
}

Primero importamos el ADD_FETCHED_DATAtipo de acción y luego definimos y exportamos una función pura que toma el estado y la acción anteriores y devuelve un nuevo estado dependiendo del tipo de acción. En este caso, si ADD_FETCHED_DATAse envía la acción, simplemente devolvemos un nuevo estado con la carga útil de la acción (la matriz de datos extraídos de la API JSON).

A continuación, abra el reducers/favoritesReducer.jsarchivo:

$ nano reducers/favoritesReducer.js

Y agregue el siguiente código:

[~/javascriptjargon/src/reducers/favoritesReducer.js]

import { ADD_FAVORITE_TERM, REMOVE_FAVORITE_TERM } from '../actions/types';

export default function favoritesReducer(state = [], action) {
    switch (action.type) {
        case ADD_FAVORITE_TERM:
            return [...state, action.payload];
        case REMOVE_FAVORITE_TERM:
            return state.filter((e) => {
                if (e.name !== action.payload.name) {
                    return true;
                }
                return false;
            });
        default:
            return state;
    }
}

Nuevamente, importamos los tipos de acción ADD_FAVORITE_TERMREMOVE_FAVORITE_TERM, luego definimos y exportamos una función pura que toma el estado anterior y una acción, y devuelve un nuevo estado dependiendo de la acción.

Si el tipo de acción es ADD_FAVORITE_TERM, creamos un nuevo estado compuesto por el estado anterior y el nuevo término favorito enviado con la carga útil de la acción. Si es así REMOVE_FAVORITE_TERM, llamamos al método de filtro en la matriz de estado para eliminar el término por nombre del estado. Si no se envía ninguna de estas acciones, devolvemos el estado anterior.

Ahora hemos creado reductores para mutar las distintas partes del estado global de nuestra aplicación. Necesitamos combinar estos reductores en un reductor usando el método combineReducers () . Abra el reducers/index.jsarchivo:

$ nano reducers/index.js

A continuación, agregue el siguiente código:

[~/javascriptjargon/src/reducers/index.js]

import { combineReducers } from 'redux';
import termsReducer from './termsReducer';
import favoritesReducer from './favoritesReducer';

export default combineReducers({
    terms: termsReducer,
    favorites: favoritesReducer
});

Primero importamos el combineReducers()método y nuestros dos reductores de sus respectivos archivos. A continuación, llamamos al combineReducers()método pasando un objeto que toma las claves que se utilizarán para cada segmento de nuestro estado global y asigna el reductor requerido.

El combineReducers()genera una función que llama el reductor requerida para cada rebanada del estado, y combina sus resultados en un solo objeto.

Para obtener información más detallada sobre los reductores, asegúrese de leer esta página de los documentos oficiales.

En el siguiente paso, veremos cómo configurar la tienda Redux en nuestra aplicación.

Paso 5: creación de la tienda React Redux

Ahora que hemos definido las acciones y los reductores en nuestra aplicación, necesitamos crear la tienda.

Abra el src/index.jsarchivo:

$ nano index.js 

A continuación, comience agregando las siguientes importaciones:

[~/javascriptjargon/src/index.js]

import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
import { fetchData } from './actions'

A continuación, cree la tienda de la siguiente manera y envíe la acción para obtener datos de la API JSON:

[~/javascriptjargon/src/index.js]

const store = createStore(rootReducer, applyMiddleware(thunk));
store.dispatch(fetchData());

Primero, creamos la tienda y aplicamos el redux-thunkmiddleware a la tienda, lo que nos permite admitir acciones asincrónicas en Redux.

A continuación, enviamos nuestra primera acción para obtener datos del servidor y almacenarlos en la tienda.

A continuación, debemos pasar la tienda a los componentes. En el mismo archivo, envuelva el Appcomponente con el Providercomponente de la siguiente manera:

[~/javascriptjargon/src/index.js]

ReactDOM.render(
    <Provider store={store}>
      <App />
    </Provider>,
    document.getElementById('root'));

Pasamos la tienda como atrezzo <Provider>.

En el siguiente paso, veremos cómo crear un componente React para mostrar nuestros datos.

Paso 6: creación del componente React

En este paso, crearemos un JargonListcomponente para mostrar la lista de terminologías JS que ha consumido de la API. También mostraremos los términos favoritos seleccionados por los usuarios en este mismo componente y usaremos la representación condicional para cambiar entre las listas de términos y favoritos.

Regrese a su terminal y cree un JargonList.jsarchivo en la src/carpeta de su proyecto:

$ touch JargonList.js 

Abra el JargonList.jsarchivo:

$ nano JargonList.js

A continuación, comience agregando las siguientes importaciones:

[~/javascriptjargon/src/JargonList.js]

import React from 'react';
import { connect } from 'react-redux';
import { addFavoriteTerm, removeFavoriteTerm } from './actions';

A continuación, defina el siguiente método que se utilizará para mapear el estado de la tienda Redux a los accesorios del componente:

[~/javascriptjargon/src/JargonList.js]

const mapStateToProps = state => {
    return {
        terms: state.terms,
        favorites: state.favorites
    };
};

A continuación, creemos el componente de la siguiente manera:

[~/javascriptjargon/src/JargonList.js]

class JargonList extends React.Component {

    state = {
        showFavorites: false
    }

    render() {
        if (this.state.showFavorites) {

            return (
                <div>
                    <h1>
                        JS Jargon
                    </h1>
                    <div>
                        <button onClick={() => { this.toggleJargon() }} > Show Jargon</button>
                    </div>
                    <div>
                        {this.props.favorites.map((term, index) => {
                            return (
                                <div key={index}>
                                    <h1> {term.name}</h1>
                                    <p> {term.description}</p>
                                    <button onClick={() => this.props.dispatch(removeFavoriteTerm(term.name))}>
                                        Remove from favorites
                                    </button>

                                </div>
                            );
                        })}                
                    </div>
                </div>
            )
        }
        else
            return (
                <div>
                    <h1>
                        JS Jargon
                    </h1>
                    <div>
                        <button onClick={() => { this.toggleFavorites() }} > Show Favorites</button>
                    </div>
                    {this.props.terms.map((term, index) => {
                        return (
                            <div key={index} >
                                <h1> {term.name} </h1>
                                <p> {term.description}</p>
                                <button onClick={() => this.props.dispatch(addFavoriteTerm({ name: term.name, description: term.description }))}>
                                    Add to favorites
                        </button>


                            </div>
                        );
                    })}

                </div>
            )
    }
}

A continuación, necesitamos definir los siguientes dos métodos en la JargonListclase para alternar entre la jerga y las vistas de favoritos:

[~/javascriptjargon/src/JargonList.js]

    toggleFavorites() {
        this.setState({ showFavorites: true });
    }
    toggleJargon() {
        this.setState({ showFavorites: false });
    }

Finalmente, necesitamos conectar el componente a la tienda Redux y exportarlo:

[~/javascriptjargon/src/JargonList.js]

export default connect(mapStateToProps, null)(JargonList);

El connect()método le permite acceder al método de envío como un accesorio al devolver un nuevo componente con el método de envío como su accesorio.

A continuación, abra el src/App.jsarchivo:

$ nano App.js

A continuación, actualícelo de la siguiente manera:

[~/javascriptjargon/src/App.js]

import React from 'react';
import JargonList from './JargonList';


function App() {
  return (
      <JargonList />    
  );
}

export default App;

Simplemente incluimos nuestro JargonListcomponente en nuestro Appcomponente para que se procese cuando se inicia la aplicación.

A continuación, veremos cómo conservar los términos favoritos usando localStorage.

Paso 7: guardar datos en el almacenamiento local

En este paso, agregaremos soporte para almacenar los términos JS favoritos agregados por el usuario usando el almacenamiento local del navegador para que puedan persistir entre las actualizaciones de la aplicación.

Abra el src/index.jsarchivo:

$ nano index.js

A continuación, implementemos los siguientes cambios.

Primero, necesita definir estos dos métodos:

[~/javascriptjargon/src/index.js]

const saveState = (state) => {
  if(state.favorites.length !== 0){
    localStorage.setItem("state", JSON.stringify(state));
  }
};

const getState = () => {
  try{
    const s = localStorage.getItem("state");
    if (s  === null) return undefined;
    return JSON.parse(s);
  }catch(e){
    return undefined;
  }
};

La saveState()función toma un objeto de estado y lo guarda en localStorage, si la matriz de favoritos del objeto de estado no está vacía, usando el método setItem () que toma una clave de "estado" y una cadena que representa el estado después de convertirlo de un JavaScript objeto a una cadena usando el JSON.stringify()método.

La getState()función obtiene el estado al localStorageutilizar el getItem()método para recuperar la cadena almacenada y el JSON.parse()método para convertirla de nuevo en un objeto JavaScript.

Finalmente, necesitamos recuperar el estado guardado de localStorage y pasarlo como el estado inicial de la tienda:

[~/javascriptjargon/src/index.js]

const initialState = getState();
const store = createStore(rootReducer,initialState, applyMiddleware(thunk));

De esta forma, cuando el usuario vuelva a visitar la aplicación, la tienda se inicializará con los datos favoritos de localStorage.

Finalmente, necesitamos suscribirnos a la tienda Redux y llamar a la saveState()función con los favoritos del usuario cada vez que se envía una acción.

[~/javascriptjargon/src/index.js]

store.subscribe(()=>{
  saveState({
    favorites: store.getState().favorites   
  })
})

De esta forma, cuando enviamos una acción para agregar un favorito o eliminar un favorito de la tienda se actualizará el almacenamiento local correspondiente.

Este es el código completo del src/index.jsarchivo después de estas actualizaciones:

[~/javascriptjargon/src/index.js]

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';

import rootReducer from './reducers';
import { fetchData } from './actions';


const saveState = (state) => {
  if (state.favorites.length !== 0) {
    localStorage.setItem("state", JSON.stringify(state));
  }
};

const getState = () => {
  try {
    const s = localStorage.getItem("state");

    if (s === null) return undefined;
    return JSON.parse(s);
  } catch (e) {
    return undefined;
  }
};

const initialState = getState();
const store = createStore(rootReducer, initialState, applyMiddleware(thunk));
store.dispatch(fetchData());

store.subscribe(() => {
  saveState({
    favorites: store.getState().favorites
  })
})

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root'));

serviceWorker.unregister();

Conclusión

En este tutorial, hemos visto paso a paso cómo podemos construir una aplicación React y administrar su estado usando Redux.

La aplicación que hemos creado es una aplicación simple de jerga de JavaScript que se inspira en la jerga de JavaScript simplificada disponible en este repositorio .

Puede encontrar el código fuente de esta aplicación en este repositorio de GitHub .

Puede encontrar más detalles en los documentos oficiales de React y Redux .

No hay comentarios.:

Publicar un comentario

Dejanos tu comentario para seguir mejorando!

outbrain

Páginas