js -react ejemplo useReducer con fetch y bootstrap 5

React hook useReduce con fetch

ejemplo carga con fetch en react acabando con estado de exito y error
Ejemplo fetch success y error en react con useReduce

En react para trabajar con el estado solemos recurrir a useState y useEffect. Esto está bien cuando es un estado sencillo como el siguiente ejemplo:

function Ejemplo() { const [nombre, setNombre] = useState("") useEffect(()=>{ setNombre("Eduardo A. F.") },[]) return ( <span><b>Nombre:</b> {nombre}</span> ) }

Cuando tenemos que manejar un estado más complejo lo más conveniente es recurrir a un gestor de estado global; concretamente a una función actualizadora de estado llamada función reductora o reducer.
Esta función recibe dos parámetros. El nuevo estado y la acción. En el ejemplo coincide que las dos acciones actualizan de la misma forma el estado. Algo como lo siguiente:

const fn_reducer = (state, action) => { switch(action.type) { case ACTIONS.FETCH_SUCCESS: case ACTIONS.FETCH_ERROR: return { error: action.error, loading: action.loading, products: action.payload } default: return state } }

El código

Este snippet carga el listado que se muestra en la imagen anterior.

import { useReducer, useEffect } from "react" import "../css/reducer.css" const URL_PRODUCTS = "https://json.theframework.es/index.php?getfile=app_product.json" const ACTIONS = { FETCH_SUCCESS: "FETCH_SUCCESS", FETCH_ERROR: "FETCH_ERROR" } //nuestro estado más complejo const stateproducts = { loading: true, error: "", products: [] } const fn_reducer = (state, action) => { switch(action.type) { case ACTIONS.FETCH_SUCCESS: case ACTIONS.FETCH_ERROR: return { error: action.error, loading: action.loading, products: action.payload } default: return state } } function Reducer() { //el estado y su setter que es un dispatcher //creamos unas constantes que son "copias" del reducer y el estado complejo const [state, dispatch] = useReducer(fn_reducer, stateproducts) /* //usando fetch como promesa, hace lo mismo que con async y await useEffect(() => { fetch(URL_PRODUCTS) .then(response => response.json()) .then(data => dispatch({ type: ACTIONS.FETCH_SUCCESS, error: "", payload: data })) .catch(ex => dispatch({ type: ACTIONS.FETCH_ERROR, error: ex.message, payload: [] })) }, []) */ //usando fetch con async y await useEffect(()=>{ (async () => { try { const response = await fetch(URL_PRODUCTS) if( !response.ok ) { throw new Error(`HTTP error! status: ${response.status}`) } const data = await response.json() dispatch({ type: ACTIONS.FETCH_SUCCESS, error: "", payload: data }) } catch (ex) { console.log(ex.message) dispatch({ error: ex.message, type: ACTIONS.FETCH_ERROR, payload: [] }) } })() },[]) return ( <> <div className="center"> <h2>Productos</h2> <span className="status"> Estado: { state.error ? <h1 className="badge bg-danger">{state.error}</h1> : <h1 className="badge bg-success">Ok</h1> } </span> </div> <div className="grid mt-3"> <div className="center"> <ul className="list-group"> {state.loading ? "Loading" : state.products.map(product => <li key={product.id} className="list-group-item d-flex justify-content-between align-items-start"> <div className="ms-2 me-auto"> <div className="fw-bold">{product.name}</div> {product.description} </div> <span className="badge bg-primary rounded-pill">{product.id}</span> </li> ) } </ul> </div> </div> </> ) } export default Reducer import TestReducer from "./components/reducer" function App() { return <TestReducer /> } export default App

El código fuente completo lo dejo en mi Github

Autor: Eduardo A. F.
Publicado: 16-07-2021 23:11