Capitulo 12 del Módulo 2 Carrito de compras - REACT

➜ Terminando el carrito y consumiendo apis con AXIOS

Terminando el carrito y consumiendo apis AXIOS (12) | React Básico | La última lección del curso, terminaremos todo lo referente al carrito y cambiaremos nuestra fuente de datos de un archivo plano a una API.

1.- El spread operator

Habíamos dejado nuestro avance hecho hasta el punto de tener el carrito mostrandose en el sitio, si intentamos agregar un curso a este, tal curso si aparecerá en el carrito, pero si intentamos agregar otro, este nuevo curso reemplaza al anterior, no se agregá al carrito sumándose al anterior, sino que más bien, sobreescribe el contenido del array a solo tener un valor de nuevo; eso sucede porque en el código simplemente tienes esta línea:

         setContenidoCarrito([curso])

Dicha línea sólo le da al estado un nuevo y único “curso” cada vez, para corregirlo debo introducirles un concepto del que hasta ahora no he hablado, se trata del spread operator; recuerda que lo que queremos es que se agreguen los cursos uno tras de otro en el array que tenemos en nuestro estado “contenidoCarrito”; por lo que la solución sería ir agregando valores al array, una forma de hacer esto lo vimos en la unidad uno, con push ¿recuerdas? 

         setContenidoCarrito(contenidoCarrito.push(curso))

Pero push no nos servirá, (además que la línea anterior no debería ser el argumento de la función set) porque como ya mencione dos lecciones atrás, tú no debes modificar tu state directamente, o bueno igual y si puedes, pero hay una gran razón para no hacerlo, ni con push, ni igualandole directamente un nuevo valor, ¿y por qué? porque para eso existen las funciones set que extraes cada que creas un estado, con el valor que le das a la función set, estas actualizando el valor de un estado, así que ese es el problema, cómo agregamos valores al estado, sin alterar el estado mismo, es decir lo único permitido es actualizarlo con su función set ¿como podriamos hacer? pues una solución es con el spread operator, antes de mostrarte cómo funciona, probemos algo, si creas un nuevo array que tenga el contenido del carrito, y a ese array le agregas el curso que se haya clicado, para que así luego le des ese array a la función set, ¿funcionaria?¿lograrías actualizar el estado? pues no habría un error, porque no estamos alterando el state directamente, oh eso parece.

        const array = contenidoCarrito;
        array.push(curso);
        setContenidoCarrito(array)

El código anterior realmente no va a funcionar por una sencilla razón, no se si lo sepas, pero cuando tu asignas el valor de un array con otro array, no estás creando una copia estas pasando un valor por referencia, ¿y referencia a donde? pues en esta caso, en referencia a tu estado, así que nuevamente, estás alterando el estado, por eso lo anterior no va funcionar, entonces, el spread operator o operador de propagación ¿como resuelve este problema? pues haciendo que el array se expanda, y bueno hacer que se expanda, o solo expandir, es un traducción no tan exacta de spread, pero se refiere tanto a agregar nuevo contenido al array como a hacer una copia del mismo, me explico, es cuando quieres incluir en un nuevo array, u objeto, los elementos de un array, u objeto ya existentes, porque si, la también llamada sintaxis spread puede aplicarse en objetos, y hacer una copia es justo lo que queremos hacer, no tener una referencia al estado, que es lo que conseguimos hasta ahora, por lo que para ello tienes que hacer este cambio:

        const array = [...contenidoCarrito];
        array.push(curso);
        setContenidoCarrito(array)

Esos tres puntos son la famosa spread syntax, y hay tres lugares en los que tu puedes usarlo: en un objeto, en los argumentos de una función, y para nuestro caso, en arrays; con ese simple cambio ya tenemos lo que queremos, una copia, por lo que aplicar el push ya funcionaria.

2.- UseState y las funciones set

¿Qué pasa si intentamos probar el código sin el operador spread? si quitamos los tres puntos, y lo ponemos todo como estaba antes van a notar el problema que surge de editar el estado directamente, que es, no tener una respuesta visual, (ni siquiera en consola) si agregas un curso al carrito, este no se mostrará dentro del mismo y ¿por qué no se agregó el curso? bueno, de eso te hable en la lección 10, no puedes editar el estado directamente, porque cuando lo haces así, incluso usando su función set, no habrá rerenderizado, recuerda que al igualar el array al valor del estado (asignación) el array se vuelve una referencia que apunta al estado mismo, no estás creando una copia, ¿y de donde viene eso de no editar el estado? pues de la misma documentación:

no-edites-el-estado

A pesar de usar la función set, se omite el renderizado porque array y estado son el mismo objeto, ojo solo se omite el renderizado, si tú provocas otro renderizado manualmente, notaras que al final si se cambio el contenido del carrito, ahí estaran el curso que clicamos antes, pero aver, ¿tu para que quieres alterar el estado si no para mostrar un cambio? por eso digo que es una razón de peso, tu lo que quieres es el renderizado para mostrar tus cambios y eso no lo tendrás si no sigues la reglas de React.

imagen1_

imagen2_

imagen3_

imagen4_

Les menciona que el operador spread se podía usar en los argumentos de una función, en objetos y en los arrays; por lo que podemos aprovecharnos del primero de esos casos, para usarlo directamente como argumento de la función set, y así agregar el curso clicado al final del array, como un nuevo elemento, reduciendo todo a una línea porque ya no necesitaremos del push. 

         setContenidoCarrito([...contenidoCarrito, curso]) 

3.- Terminando las funcionalidades del carrito:

3.1.- Borrar cursos del carrito

Con el carrito agregando cursos correctamente, ya podemos avanzar con lo siguiente, el borrado, hay que hacer que los botones de borrar y el gran botón de vaciar carrito, funcionen, el proceso es similar a lo trabajado con manejador click curso, primero procedemos con una nueva función, que se llamara manejador click equis, que requerirá de parámetro, el id del curso:

          const manejadorClickX = id => { }

En el cuerpo de la función vamos a crear una constante llamada “nuevoContenido”, que va a filtrar el contenido del carrito según si el curso tiene o no el mismo id, es decir, recorremos uno a por uno los cursos del carrito, con filter, y si el curso tiene el mismo id que el dado como parámetro, no lo incluimos en la constante, 

          const nuevoContenido = contenidoCarrito.filter( curso => curso.id !== id);

¿y de dónde sale el id? pues va ser el id del curso que se quiere borrar del carrito, recuerda que en el componente carrito estamos armando una fila con cada curso que llega al carrito y como tenemos una fila donde está la “equis”, es allí donde pondremos el manejador click equis, además como también tenemos ahí el objeto curso con toda su info, (lo recuperamos del estado contenidoCarrito) de ahí sacamos el id para pasarlo a la función.

componente_carrito

El resto de pasos los repetimos muchas veces la lección anterior, tienes que extraer la función “manejadorClickX” del contexto Tienda y poner disponible la función en el proveedor con todo eso listo, ya puedes probar el borrado de cursos del carrito. (si van a funcionar)

3.2.- Vaciar el carrito

A diferencia de los botones individuales para borrar cada curso, el botón vaciar carrito, debe quitar todos los cursos que hayan hasta el momento, lograr esto con todo lo que ya sabemos será mucho más fácil, requeriremos una nueva función, que se llamara manejador clic vaciar, y lo único que va ha hacer es actualizar el estado a un array vacío:

          const manejadorClickVaciar = () => setContenidoCarrito([]);

Creamos la función y la agregamos a los valores del proveedor, luego en el componente carrito, extraemos dicha función del contexto y buscamos el botón vaciar carrito, que es una etiqueta a, (así era en la unidad uno eres libre de cambiarlo a button si gustas), y allí le agregas el onclick.

imagen_vaciar_carrito

4.- ¿Qué pasa si agrego dos veces el mismo curso?

Un detalle importante a tener en cuenta es que en carrito.jsx tenemos una key, recuerda que las keys no se debe repetir, pero eso es posible que pase porque estamos usando para cada elemento el id del curso, por lo que si ingresas al carrito, dos veces el mismo curso, tendrías un error porque habría dos elementos con la misma key, para evitar que eso pase, en la función manejadorClickCurso, voy a agregar un if, que dentro tendrá al array de contenidoCarrito usando la función some, some comprueba si al menos un elemento del array cumple con la condición dada como callback, si al menos un elemento cumple, se retorna true, lo que significaria que es un curso repetido, porque la condición del callback compara los ids de todos los cursos del array con el id del curso que queremos agregar.

        if ( !contenidoCarrito.some(unCurso => unCurso.id === curso.id)) {
            setContenidoCarrito([...contenidoCarrito,curso])
        }

5.- Introducción a Axios y fetch:

Ya terminamos lo referente al carrito, el curso podría terminar aquí, pero quiero que nos detengamos en cómo estamos consumiendo los datos, hasta ahora solo hemos estado usando un fichero de texto plano al que llamamos datos, pero ese es un escenario que no se repite en la vida real, lo correcto sería consumir los datos vía api, para ello ya tengo preparado dos endpoints tanto para cursos como para las áreas, entonces, ¿cómo usamos una api en lugar de un archivo de texto plano? pues voy a mostrarte dos formas, la primera será usar axios, y la segunda usar fetch. Mientras que fetch es una función nativa del navegador, axios es una librería que requiere instalación, para ello abre una consola y usa el comando:

         npm i axios          

5.1.- Consumir las áreas desde una api con Axios

Axios no tarda mucho en instalarse, es bastante rápido; ahora, para usar axios primero necesito hablarles del último hook que veremos en el curso, el que nos faltaba, useEffect, dejame resumirte que hace este hook en una sola frase, crear un efecto, ¿a qué me refiero con efecto? pues a una función que pasamos como primer argumento del useEffect y que será el efecto que nosotros queramos que suceda, en el ejemplo a continuación el efecto es una función fecha:

    useEffect(() => { 
        async function recuperarAreas() { 
            const {data} = await axios('http://127.0.0.1:8000/api/areas'); 
            setListaAreas(data.data); 
            setSeleccion(data.data[0]); 
        } 
        recuperarAreas() 
    },[]); 

Un detalle a tener en cuenta es que “recuperarAreas” está siendo declarada y usada dentro del mismo useEffect, aunque lo normal es declararla afuera, también funciona de esa forma, otro detalle es que es una función asíncrona, porque la función recupera en una constante llamada data lo que nos llegue de la función axios, y como axios hace peticiones http, necesitamos esperar esa petición http, para eso es la palabra reservada “await”, lo que axios retorna en data es un objeto con un array llamado “data”, dicho array contiene las áreas que necesitamos para el estado listaAreas y el estado selección, ahora, falta algo, ¿cuándo se va a ejecutar este efecto? pues para eso, es el segundo argumento del useEffect, que es la lista de dependencias, es opcional, si no lo pasas es que el que código se ejecutará cada vez que se renderize el componente en el que estamos, lo cual puede hacer que sea muchas veces por ello si quieres que solo ejecute cuando se renderiza por primera vez el componente, tienes que poner un array vacío, es decir sin ninguna dependencia.

5.2.- Consumir los cursos desde una api con Fetch

Antes de ver el ejemplo con fetch, no olvides quitar todas las partes donde se usaba el array áreas para evitar errores; ahora vamos al componente de inicio, y esta vez usaremos fetch; primero va lo mismo de antes, useEffect, y la función que va en el primer argumento del useEffect va ser “recuperar cursos filtrados”, función que es declarada fuera, porque no es necesario crear la función dentro, en el ejemplo anterior con axios lo hice asi, pero tambien puedes hacerlo de esta otra forma:

  async function recuperarCursosFiltrados() { 
    const respuesta = await fetch('http://127.0.0.1:8000/api/cursos') 
    const {cursos} = await respuesta.json() 
    setCursosFiltrados(cursos.filter(unCurso => (unCurso.area_id === seleccion.id))); 
  } 

Entonces, dentro vamos a tener casi lo mismo, una constante “respuesta” que va a esperar a que fetch obtenga el array con los cursos; pero aquí viene lo diferente, una constante “cursos”, que va a volver a esperar a que la respuesta se convierta a json; fijense que mientras en el ejemplo con axios se desestructura directamente lo que retornaba axios, ahora tenemos que esperar a que “respuesta” pase a json, no podríamos desestructurar respuesta porque respuesta no retorna el contenido del endpoint, retorna un objeto response con datos como el estado de la petición, o los headers, es recién usando json que obtenemos el contenido del endpoint, entiendo que todo esto puede ser confuso si nunca te has enfrentado a la asincronía de javascript, por ello es que te presenté la opción de axios primero, que no requiere de un paso extra y te permite consumir la data directamente, por eso Axios es mi recomendación por si aún no dominas la asincronía. Por cierto seguro notaste que hay un “setCursosFiltrados” dentro de la función, eso es porque necesitaremos un estado que almacené los cursos ya filtrados, en reemplazo del array “areas” del archivo de texto plano:

const [cursosFiltrados, SetCursosFiltrados] = useState([]);

Ese estado debe iniciar siendo un array vacío, porque el llenado de dicho estado, va suceder en la misma línea que el filtrado, todo dentro de la función efecto del hook useEffect. Por último nos falta decidir cuándo se va a lanzar el efecto, a diferencia de las áreas, no basta con que el efecto salte solo al crearse el componente, tiene que saltar cada que el estado seleccion cambie, asi que dentro del array que es el segundo argumento del useEffect pondremos el estado seleccion:

useEffect(() => {recuperarCursosFiltrados() },[seleccion]);


678 visitas

Recursos descargables de la lección 12
  • : [ leccion12-final(sinnodemodules).zip ]
  • Debes iniciar sesión para descargar los recursos de la lección.
  • Descarga el código del proyecto

    Descarga el código fuente del proyecto adquiriendo el curso completo

    Comprar

    ¡Qué aprenderás?

    tooltip bs-tooltip-top bs-tooltip-end bs-tooltip-bottom bs-tooltip-start show fade tooltip-inner

    Codea Applications

    México, Colombia, España, Venezuela, Argentina, Bolivia, Perú