Curso ReactJS Básico
Creando un proveedor para el contexto (11) | React Básico
Esta es la lección más larga del curso, aprenderemos sobre el contexto y ahondaremos en el proveedor, aplicándola en crear un filtro para nuestra tienda.
El estado no es el único hook, en la lección anterior te decía que los hooks son como características que le damos a nuestros componentes, ya vimos una, el estado, pero hay más, y de la que les hablaré ahora, es del contexto, el contexto es lo que permite que un componente reciba información de otros componentes sin pasar esa información como props, imaginate que dentro de un componente estás usando a otro componente, algo completamente normal, porque de esa forma puedes pasar un prop del componente padre, al componente hijo, ahora, eso puede convertirse en una tarea complicada si tienes que pasar el prop a través de múltiples componentes, es decir imagina que tienes un componente padre con, hijos, y hasta nietos y que quieres pasarle el prop a uno de esos nietos; serían muchos componentes por los que pasar ¿no? bueno, para esos casos, puedes usar un contexto, porque el contexto permite que cierta información de un componente padre esté disponible en cualquier componente que esté por debajo de él, sin pasar la información explícitamente por medio de props. Vamos a ver a fondo cómo es esto, para hacer uso del contexto, hay que seguir tres pasos.
Primero debemos crear y exportar el contexto, todo ello lo haremos en main, (solo con fines didácticos) en una constante llamada “contexto tienda” guardaremos un objeto contexto, los objetos contexto los obtenemos con la función createContex, estos objetos tienen dos propiedades, consumer, que es una forma, algo anticuada de pasar el contexto a los componentes; y la más importante, la propiedad provider, que es la forma definitiva de pasar el valor del contexto a los componentes, ¿cuál valor? pues la idea es que pasemos el contenido o valor del contexto, de la forma que ves en la siguiente imagen, envolviendo toda la aplicación, es decir, la propiedad provider de contexto tienda es la etiqueta que está envolviendo al resto; de esa forma el contenido de la propiedad value del provider (la que tiene el estado “lista Areas”), estará disponible en toda la aplicación.
1.2.- Pasar el valor del contexto
El paso dos es pasar el hook, o simplemente usar el hook en algún componente que lo requiera, y el primer componente que leerá nuestro contexto va ser barra lateral, para ello vamos a crear una constante llamada “listaAreas” que con el hook “useContex”, al que le pasamos el nombre del contexto, vamos a darle el valor que tiene dicho contexto; luego usaremos map en lista Areas, (lista áreas también es el nombre del valor puesto en el contexto que creamos en main) para recuperar cada valor del array áreas, y así usar las propiedades que necesitemos en el componente, como el id de cada área (para usarla como key) o la propiedad icono (para el source de la imagen) y nombre (para el span), con todo esto el navegador debe mostrarnos todo como antes ¿no? pues no, cuando pruebes tendrás un error.
1.3.- Llamada inválida al hook ¿por qué sucede?
lo que pone el error de la imagen siguiente es que los hooks solo se pueden llamar dentro del cuerpo de la función de un componente y nos da aquí tres posibles razones, de porque pasa eso, pero es mejor explicar en el código que está fallando, primero comenta los cambio que hicimos, temporalmente, y en main convertimos en un string simple el valor del contexto, “lista áreas”; (con ello no va a haber error, porque estas pasando un string a toda tu app), si guardamos y vamos al navegador, el error desaparece, pero también el contenido de la barra lateral; el error pasaba porque el problema no es el contexto sino el estado lista area que creamos, verán, el estado es un hook que solo debe aplicarse en componentes, main no es un componente; por otro lado la razón por la que lo pongo el contexto y el estado en main es para tener cercanía con el árbol de toda la aplicación, aunque ya te digo, no es normal tener contextos ni estados en el main, y recuerda que creamos el estado para usarlo con el contexto, si quito el estado, debo quitar tambien ese contexto, pero si hago eso, entonces ¿donde deberia crear el contexto?
2.- Proveedores
Habíamos dicho que para pasar el valor del contexto usamos los providers ¿no? bueno, pues estos te los puedes llevar a otro archivo, dado que no es una buena práctica tener todo en main, y que además el estado nos está dando error, lo mejor sería llevarnos el código a un componente. (ojo que create context no es el hook, useContext es el hook) Vamos a crear una nueva carpeta llamada “contexto” que dentro tendrá un archivo llamado “tienda.jsx” y ahí crearemos una función llamada “proveedor tienda” donde movemos el código que pusimos en main ¿y que retornar la función? pues el proveedor del Contexto tienda, para que lo entiendas mejor, respondamos a la pregunta ¿que nos retorna la función createContex? esto no lo dije antes, pero retorna un objeto contexto que sirve como un high order component, high order component es un concepto que ya no se encuentra en la documentación actual, pero que en resumen, es un componente padre que puedes usar como una etiqueta que envuelva a otras en el árbol de componentes de tu aplicación, es decir como un componente padre, esto significa que todo el proveedor Tienda es un componente, por ello ya no nos daría error el tener aquí el estado y el contexto.
¿Recuerdas que te dije que eran tres pasos para hacer uso del contexto? eso no me lo he inventado, lo encuentras en esta página, él pasó tres es envolver a los hijos con el provider; lo que hicimos en main, pero ahora aquí, aunque se debe aclarar un par de cosas, no siempre es necesario que toda la aplicación use un contexto, de hecho la razón por la que el archivo se llama ”tienda” es porque el contexto incluirá todo lo referente a la tienda online, por ejemplo, las áreas que salen en la barra lateral, o los eventos de cada click, de la etiqueta a, en el componente de barra lateral.
3.- Hacer que el contexto tienda retorne un objeto
En barra lateral voy a crear mi manejador click área, ¿de donde va ha venir? pues al igual que listaAreas va a venir del contexto tienda que tenemos en el proveedor tienda; pero surge un problema, el contexto que tenemos solo tiene un valor (listaAreas), ¿como hacemos para que pueda tener más de uno? y así poder enviarnos también el manejador click área que necesitamos en barra lateral, la respuesta a eso es hacer que el contexto tienda nos retorne un objeto, y si hablamos de objetos, podemos desestructurar sus valores para no tener que extraer el contenido uno por uno (no olvides corregir la ruta, porque el contexto ya no viene del main, sino de tienda). En la imagen a continuación puedes ver cómo se coloca un objeto como valor del contexto tienda:
Creo que hasta aquí se entiende la idea ¿no? Tienda es el contexto que nos proporciona datos referentes a la tienda online, y así como tienda, podría haber un contexto login o un contexto panel administrativo, etc, etc, según lo necesites en tu aplicación; antes de probar todo esto ¿cómo usamos nuestro ProveedorTienda? para usarlo debemos hablar de un prop único en su tipo llamado children.
Ya te habia dicho antes que el contexto tienda es un componente de orden superior (high order component), útil para envolver a los componentes que quieran usar el contexto tienda; aunque aquí hay un detalle, fijate en la imagen anterior, ContextoTienda.Provider usa una etiqueta de apertura y otra de cierre; que es algo que no solemos hacer ¿no? para usar un componente tú normalmente pones tu componente en una línea, y ya, pero hacerlo con etiquetas de apertura y cierre tiene una ventaja, extraer el prop children.
Children es un objeto que contiene los elementos que envuelve un componente, cuando tú envuelves algo de jsx con un componente ese algo se pasa en el prop children, esto abre la posibilidad de usar el contexto tienda en main como un envoltorio para así decidir que parte de la aplicación tendrá acceso al contexto, cumpliendo con la 3ra regla del uso del contexto; aunque ojo no es obligatorio siempre crear un proveedor aparte, el createContext lo puedes usar fuera de un componente, (fuera de la función) como dentro, por lo que si quieres crear un contexto dentro de una función y no en un archivo aparte, puedes hacerlo, y luego usarlo para envolver algún punto de tu return, o todo el return, no es que siempre tengas que sacar afuera el proveedor, pero eso dependera de ti, para el carrito que hacemos, no es necesario más de un contexto.
5.- ¿Cómo hacer un filtro para los cursos?
Si probamos lo hecho hasta ahora en el navegador, todo funciona correctamente, console.log incluido, por lo que ya podemos pasar a otro tema, el filtrado, en nuestro archivo de tienda voy a necesitar un nuevo estado que llamaré “selección” y lo iniciare con una área, recuerda que las áreas vienen de un array en el archivo de datos, así que hay que tomar el primer valor de ese array, ¿porque el primero? bueno realmente no importa podría ser la que gustes que se muestre primero, y para el ejemplo usare el área backend que tiene dos cursos que deberían mostrarse primero.
Ahora bien, cada que se seleccione una nueva área, quiero que el cambio podamos verlo visualmente en el componente cabecera, para ello en el archivo de dicho componente voy a agregar el contexto tienda para extraer el estado que acabamos de crear, seleccion, como selección era el área en la posición cero, y cada área tiene una propiedad nombre, voy a cambiar el h1 que se ve en la imagen siguiente, por la propiedad nombre del área seleccionada (backend).
Esto lo que hará es que al arrancar la aplicación, veamos primero los cursos de backend, pero falta que cambien los cursos cuando clico sobre un área, para ello ya teníamos una función, manejador click área, así que vamos a hacerle unos cambios, primero creo una constante, que se llame “área seleccionada” cuyo propósito va ser cambiar nuestro estado selección por la nueva área seleccionada, esto lo haremos filtrando el propio array de áreas, buscando dentro de él, un área que tenga el mismo id que pasaremos como argumento, ojo con esto, filter usa una función callback que deberá recibir un parámetro que representa cada valor del array, dicho parámetro lo usamos para crear una condición, y así filtrar los valores que cumplan esa condición, entonces, con el área que se clico ya encontrada, devolvemos esa área a la constante; pero filter es como map, retorna un array, así que le especificamos que solo queremos el primer valor encontrado poniendo el cero al final. Con el área que se clico guardada en “área seleccionada” solo debemos pasar su valor a la función set del estado selección.
Antes de guardar y probar esto, nos faltan dos cosas más, primero en barra lateral pasamos el id a manejadorClickArea, porque no te olvides que agregamos un parámetro a esa función, pero al colocamos el id tu no puedes dejarlo de la forma:
onClick={manejadorClickArea(area.id)}
porque la función se va a ejecutar inmediatamente, fijate en la sintaxis, la llaves de javascript hacen que se mandé a llamar la función, y no queremos eso porque apenas cargue el componente se ejecutaría la función, por ello para evitar ese comportamiento, vamos a poner todo en una función flecha, si no lo haces de esa forma no va a funcionar como debería.
onClick={() => manejadorClickArea(area.id)}
la segunda cosa que falta es, ahora sí, hacer que se filtren los cursos, así que vamos a la vista inicio, y vamos a usar nuestro estado de seleccion, ya saben como, con el contexto tienda, y también usaremos una vez más la propiedad filter, voy a crear una constante llamada cursos filtrados que usando el array de cursos va a guardar solo los cursos que tengan el id de área que sea el mismo id que tiene el estado de selección, recuerda que en el estado de selección tenemos el primer valor del array de áreas o si ya lo clicamos, el área que haya sido clicada (seleccionada) más recientemente. Con todo esto ya funcionará el filtrado de cursos.
6.- Iniciando con el componente carrito.
Ya para terminar esta lección creemos el componente carrito, el código del mismo lo encuentras al final de esta página (o en el mismo video de esta lección), ese código lo explicaremos en la siguiente lección, pero tan importante como es tener el carrito visualmente, es que funcione lógicamente, y para ello hay que preparar un par de cosas. A lo largo de esta lección hemos estado agregando contenido al contexto de tienda (Tienda.jsx) que luego usaremos en algun componente, esta vez es lo mismo, necesitaremos un estado que se encargue de conservar el como esta el carrito, si está vacío, si tiene un curso, si tiene dos, eso lo tendremos en el estado “contenidoCarrito”; otra cosa que necesitaremos es una función que se encargue de manejar los clicks que se hagan en cada curso, dicha función se llamará “manejadorClickCurso” y tendrá un parámetro que será el curso que haya clicado, por tanto tal parametro deberá agregarse al carrito, eso lo hacemos con la función set del estado “contenidoCarrito”, para que así el estado cambie, de un estado inicial que era un array vacío a un array con el curso que se haya clicado, como primer valor.
Entonces, tenemos que usar ese estado y función que acabamos de crear en el componente curso, los pasos son los mismos, importamos en el contexto Tienda y justo donde está la etiqueta figure debes colocar un onClick, que llamara a la función manejadorClickCurso con una función fecha, ya explique porque esto se hace así; y luego solo le pasamos el curso nos llega desde la vista de inicio (desde donde están todos los cursos ya filtrados por área) como parámetro.
Por último nos falta la respuesta visual de que el curso se agregó al carrito, para ello en el componente carrito voy a usar el operador ternario para renderizar diferente contenido según el contenido carrito, es decir, según nuestro estado, lo que que significa, que hay que traer nuestro contexto, para así usar el estado “contenidoCarrito”, fíjate en el código de la imagen a continuación, en las llaves se crean dos flujos alternativos para el componente, dependiendo de si el contenido del carrito está vacío, se mostrará un simple párrafo avisandonos que no hay cursos en el carrito, pero si el contenido del carrito tiene por lo menos un valor en su array, se colocará tal valor (o valores porque se recorre con el map) dentro de una tabla tabla con todos sus datos.
231 visitas
« Capítulo 10 – Primer acercamiento a los hooks
Capítulo 12 – Terminando el carrito y consumiendo apis con AXIOS »
Descarga el código fuente del proyecto adquiriendo el curso completo
Comprar© Todos los derechos reservados Codea App | ...de frente al código!!! | 2020 - 2023