No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

隆Se acaba el precio especial! Aprende Ingl茅s, AI, programaci贸n y m谩s.

Antes: $249

Currency
$209
Suscr铆bete

Termina en:

1 D铆as
9 Hrs
47 Min
31 Seg

Contador de productos en el carrito

10/31
Recursos

Aportes 49

Preguntas 5

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

Podemos usar la desestructuraci贸n: permite desempacar valores de arreglos o propiedades de objetos.
En este caso desempacamos los valores que trae ShoppingCartContex para una mejor lectura

const { count, setCount } = useContext(ShoppingCartContex)
 <button
   onClick={() => setCount(count + 1)}
 >
   +
 </button>

Como les dije antes, estamos haciendo click en un bot贸n鈥 usemos la correspondiente etiqueta button, no un div. Hagamos buenas pr谩cticas:

<button
          onClick={() => context.setCount(context.Count + 1)}
          className="absolute top-0 right-0 flex justify-center items-center bg-white w-6 h-6 rounded-full m-2 p-1"
        >
          +
        </button>

En mi navbar estoy haciendo .map a las urls entonces debo verificar si mi url tiene 鈥/cart鈥 para mostrar el contador de los productos:

import { useContext } from "react";
import { NavLink } from "react-router-dom";
import { ShoppingCartContext } from "../../Context";
import { menu1, menu2 } from "../../routes";

export const Navbar = () => {
  const context = useContext(ShoppingCartContext)

  const textDecoration = 'underline underline-offset-4'

  return (
    <nav className="flex items-center justify-between w-full py-5 px-8 text-sm fixed z-10 top-0">
      <ul className='flex gap-3 items-center'>
        {menu1.map(link => (
          <li
            key={link.text}
            className={link.className}
          >
            <NavLink
              to={link.to}
              className={({isActive})=> isActive ? textDecoration : undefined }
            >
              {link.text}
            </NavLink>
          </li>
        ))}
      </ul>
      <ul className='flex gap-3 items-center'>
        {menu2.map(link => (
          <li
            key={link.text}
            className={link.className}
          >
            <NavLink
              to={link.to}
              className={({isActive})=> isActive ? textDecoration : undefined }
            >
              {link.to === '/cart' ? `${link.text} ${context.Count}` : link.text}
            </NavLink>
          </li>
        ))}
      </ul>
    </nav>
  )
}

Los componentes: (tomado del curso de JuanDC)

Les comparto la forma en la que me parece interesante usar el useContext. Ser铆a utilizarlo en el mismo archivo del Context as铆:


Para luego no tener que importar el useContext en cada lugar en el que queramos hacer uso del context. Simplemente llamamos nuestro hook que lo llama internamente. Ejemplo:

mejorar performance del +:
algo que podemos hacer para mejorar la experiencia de usuario es poner una acci贸n en el bot贸n del + para que el usuario sepa que est谩 encima de 茅l, en mi caso le agregu茅 esta linea de c贸digo para cambiar el color de fondo cuando el mouse entra en el bot贸n y por supuesto cambiar el Div por un Button, html semantico

hover:bg-blue-500

Otra forma de hacerlo es usando un hook personalizado:

import { useContext } from "react";

import { EcommerceContext } from "../context/EcommerceProvider";

const useEcommerce = () => {
	return useContext(EcommerceContext);
};

export { useEcommerce };

Y as铆 no tienen que crear el useContext en cada componente sino que solamente deben llamar al hook y 茅ste ya contiene todas las variables del provider:

import { useEcommerce } from "../hooks/useEcommerce";

const Card = (data) => {
	const { incrementShoppingCart } = useEcommerce();
	return (
		<div className="bg-gray-200 cursor-pointer w-56 h-60 rounded-lg ">
			<figure className="relative mb-2 w-full h-4/5">
				<span className="absolute bottom-0 left-0 m-2 px-2 bg-white/70 rounded-full text-black text-xs">
					{data?.data?.category}
				</span>
				<img
					className="w-full h-full object-cover rounded-lg"
					src={data?.data?.image}
					alt={data?.data?.title}
				/>
				<button
					className="absolute top-0 right-0 m-2 flex justify-center items-center bg-white w-6 h-6 rounded-full hover:bg-black color-black hover:text-white transition-colors duration-200"
					onClick={incrementShoppingCart}
				>
					+
				</button>
			</figure>
			<p className="flex justify-between px-3">
				<span className="text-sm font-light truncate">{data?.data?.title}</span>
				<span className="text-lg font-bold">${data?.data?.price}</span>
			</p>
		</div>
	);
};

export { Card };

Lo que podemos hacer tambi茅n es directamente crear la funci贸n de aumentar el contador dentro del Context. Adem谩s podemos crear una variable 鈥渄ata鈥 con todo lo que vamos a pasarle al value para que quede m谩s limpio el c贸digo.

import { createContext, useState } from 'react';
import PropTypes from 'prop-types';

export const Context = createContext();

export const ContextProvider = ({ children }) => {
	ContextProvider.propTypes = {
		children: PropTypes.node.isRequired,
	};

	const [count, setCount] = useState(0);

	const onAdd = () => {
		setCount(count + 1);
	};

	const data = { onAdd, count };

	return <Context.Provider value={data}>{children}</Context.Provider>;
};

Hola comunidad les comparto mis apuntes de la clase, espero les sean de utilidad.
Link aqu铆:
https://www.notion.so/bg99astro/Contexto-global-8668a3e7a2ce4e398221689616a633e2

una forma de incrementar en contador sin pasar el estado solo es actualizador del estado es de la siguiente manera:

<button
  className="absolute top-0 right-0 flex justify-center items-center bg-white w-6 h-6 rounded-full m-1 p-2"
  value={0}
  onClick={() => {
    setcount((value) => value + 1);
  }}
>
  +
</button>

Card.jsx

const { count } = 
 useContext(ShoppingCartContext)

<li>Carrito{count}</li>

Context.jsx

const [count, setCount] = useState(0)

 const contextValue = {
  count,
  setCount
 }

 return (
  <ShoppingCartContext.Provider 
  value={contextValue}>
   {children}
  </ShoppingCartContext.Provider>
)

en el curso de react router vi que juanDC creava una funcion para recien usarla como constext.AnyThing

Esta es la funcion para llamar ha auth.unaFn || estado

function useAuth() {
  const auth = React.useContext(AuthContext);
  return auth;
}

luego de la importacion ha un componente se llamaba asi:

const auth = useAuth();

para luego usarla asi:

auth.myFuncionExample() 
  • luego de explicar mi logica pregunto de donde sale la variable context?? que alguien me explique porfa鈥
En el Navbar en vez de estar repitiendo codigo, pueden hacer un array de objetos con los links de la siguiente manera: ```js const navigationLeft = [ { name: 'All', href: '/' }, { name: 'Clothes', href: '/clothes' }, { name: 'Electronics', href: '/electronics' }, { name: 'Furniture', href: '/furniture' }, { name: 'Toys', href: '/toys' }, { name: 'Others', href: '/others' }, ]; const navigationRight = [ { name: 'My Orders', href: '/my-orders' }, { name: 'My Account', href: '/my-account' }, { name: 'Sign In', href: '/sign-in' }, { name: 'My Order', href: '/my-order' }, ]; ```Luego solo tienen que hacer map por cada uno: ```js {navigationLeft.map(item => { return (
  • <NavLink to={item.href} className={({ isActive }) => isActive ? activeStyle : 'flex'} > {item.name} </NavLink>
  • ) })} ```En el caso del lado derecho lo que hice para que muestre el carrito en vez del nombre del link fue esto ```js {navigationRight.map(item => { return (
  • <NavLink to={item.href} className={({ isActive }) => isActive ? activeStyle : 'flex'} > {item.href !== '/my-order' ? item.name : // Si el link es my-order mostrara el carrito <>馃洅{count} } </NavLink>
  • ) })} ```El nombre de la tienda y el correo los hice manualmente: ```js
  • <NavLink to="/"> Shopi </NavLink>
  • // ...
  • [email protected]
  • ```
    ![]()![](https://static.platzi.com/media/user_upload/plat1-e6f93287-b097-4c30-b221-275cb9997c50.jpg)Gente yo cree una funcion y luego la llame en el onclick para que se vea mas limpio el onclick
    Para el evento del card al agregar un nuevo item al carrito (+) podemos hacer uso del estado previo del state. \
    setCount(prev => prev + 1)} \> \+ \
    ```jsx
    setCount(prev => prev + 1)} > +
    ```
    Yo aparte de agregar el contador, agregue un estado nuevo para cambiar el icono de cada card para saber si ya fue agragado y si se le vuelve a dar click lo saca del carrito. \---js const { count, setCount } = useContext(ShoppingCardContext); 聽聽 const \[addCart, setAddCart] = useState(false); 聽 const addCartItem = () => {聽 聽 if (!addCart) {聽 聽 聽 setCount(count + 1)聽 聽 聽 setAddCart(!addCart)聽 聽 } else {聽 聽 聽 setCount(count - 1)聽 聽 聽 setAddCart(!addCart)聽 聽 }聽 } \---

    Asi vamos!!!

    Yo decid铆 limpiar un poco el archivo de Navbar llevandome toda la info donde se listan en objetos cada uno de los items del Navbar, este ser铆a el resultado:

    import { NavLink } from "react-router-dom";
    import { useContext } from "react";
    import { ShoppingCartContext } from "../../Context";
    import { navData } from "../../Assets/nav-data";
    
    const Navbar = () => {
        const context = useContext(ShoppingCartContext);
        const navItems = navData(context);
        const activeStyle = "underline underline-offset-4";
    
        return (
            <nav className="flex justify-between items-center fixed top-0 z-10 w-full py-5 px-8 text-sm font-light">
                <ul className="flex items-center gap-3">
                    {navItems.mainNav.map((link) => (
                        <li className={link.className} key={link.text}>
                            <NavLink 
                                to={link.to}
                                className={({isActive}) => isActive ? activeStyle : undefined}
                            >
                                {link.text}
                            </NavLink>
                        </li>
                    ))}          
                </ul>
                <ul className="flex items-center gap-3">
                    {navItems.asideMenu.map((link) => (
                        <li className={link.className} key={link.text}>
                            <NavLink 
                                to={link.to}
                                className={({isActive}) => isActive ? activeStyle : undefined}
                            >
                                {link.text}
                            </NavLink>
                        </li>
                    ))}
                </ul>
            </nav>
        );
    }
    
    export default Navbar;
    

    Y el archivo donde guardo toda la info de los items del Navbar es este:

    
    function navData(prop) {
    
        const mainNav = [
            {
                to: '/',
                text: 'Shopi',
                className: 'font-semibold text-lg'
            },
            {
                to: '/',
                text: 'All',
                className: ''
            },
            {
                to: '/clothes',
                text: 'clothes',
                className: '' 
            },
            {
                to: '/electronics',
                text: 'electronics',
                className: ''
            },
            {
                to: '/furnitures',
                text: 'furnitures',
                className: ''
            },
            {
                to: '/toys',
                text: 'toys',
                className: ''
            },
            {
                to: '/others',
                text: 'others',
                className: ''
            },
        ];
        
        const asideMenu = [
            {
                to: '/email',
                text: '[email protected]',
                className: 'text-black/60'
            },
            {
                to: '/my-orders',
                text: 'My Orders',
                className: ''
            },
            {
                to: '/my-account',
                text: 'My Account',
                className: ''
            },
            {
                to: '/signin',
                text: 'Sign In',
                className: ''
            },
            {
                to: '/shoppcar',
                text: `馃洅 ${prop.counter}`,
                className: ''
            },
        ];
    
      return {
        mainNav,
        asideMenu
      }
    }
    
    export {navData};
    
    

    La carpeta donde hice esto la llam茅 Assets/nav-data.jsx, no se porque eleg铆 esos nombres pero fue lo primero que se me ocurrio para nombrar estos archivos鈥

    Me gustar铆a leer sus comentarios para que me ayuden a darle una mejor estructura de carpetas y de nombres para la soluci贸n que hice.

    鉁 ![](

    Este art铆culo est谩 genial para entender mejor el manejo del contexto con useContext y con Redux

    Estoy haciendo de nuevo este proyecto con TypeScript y me ha costado un mont贸n pero aca les dejo mi c贸digo y mi repositorio

    archivo context .tsx

    import React, { createContext, ReactNode, useState, Dispatch, SetStateAction } from "react";
    
    type Props = {
        children: ReactNode,
    };
    
    type ShoppingCartContextType = {
        count: number,
        setCount: Dispatch<SetStateAction<number>>,
    };
    
    export const ShoppingCartContext = createContext<ShoppingCartContextType | null>(null);
    
    export const ShoppingCartProvider: React.FC<Props> = ({ children }: Props) => {
        const [count, setCount] = useState<number>(0);
        console.log('Count:', count)
    
        return (
            <ShoppingCartContext.Provider value={{ count, setCount }}>
                {children}
            </ShoppingCartContext.Provider>
        );
    };
    
    export default ShoppingCartProvider;
    

    archivo card

    import { useContext } from 'react'
    import { Product } from '../../Models/Products'
    import { ShoppingCartContext } from '../../Context'
    
    function Card(data: Product) {
        const context = useContext(ShoppingCartContext)!;
    
        const incrementCount = () => {
            context.setCount(prevCount => prevCount + 1);
        };
    
        return (
    	//Codigo de card
    	<button onClick={incrementCount}> </button>
    )
    
    ![](https://static.platzi.com/media/user_upload/image-8e7cf26a-944a-47b5-8a9e-1f27fa8809d0.jpg)
    ![](https://static.platzi.com/media/user_upload/image-46b4c4d7-069e-4415-975b-b488a9c552c9.jpg)
    Se da帽aron las rutas delas images, tienen un formato raro las urls.No se muestran
    hola. tengo el siguiente error al dar click al boton del + Uncaught TypeError: context is undefined onClick index.jsx:14 React 23 \<anonymous> main.jsx:6 favor alguien explicar como se soluciona saludos
    Mi proyecto va de la siguiente manera, lo he cambiado un poco ciertas cositas agrege iconos propiamente en lugar de poner un (+). ![](https://static.platzi.com/media/user_upload/Captura%20desde%202024-02-13%2016-33-23-17069c8e-5920-4d14-9627-c34f5de57108.jpg)
    ![](https://static.platzi.com/media/user_upload/image-87d154cb-d299-473a-b00e-e45f4e942a3a.jpg) tres horas para que se me cambien todos los contadores , jajjaja ahorita a modificarlo ![](https://static.platzi.com/media/user_upload/image-0d9bc9a5-8beb-4dfa-962f-fa3e0d0a4100.jpg)

    va quedando

    Algo que tambien se puede aplicar es que el estado global sea un arreglo que almacene todos los productos y que cada boton agregu茅 un elemento al arreglo. Al final el carrito va a reflejar la longitud de ese arreglo. Con esto podemos reflejar los productos que se agregaron al carrito. `export ``const`` AppContextProvider = ({``children``}) => {聽 ``const`` [ productsInCart, setProductsInCart ] = useState([]);` `聽 ``const`` addCartProduct = (``product``) => {聽 聽 ``const`` products = [...productsInCart];聽 聽 products.push(product);聽 聽 console.log(products)聽 聽 setProductsInCart(products);聽 }` `聽 return (聽 聽 <AppContext.Provider聽 聽 聽 ``value``={{聽 聽 聽 聽 addCartProduct,聽 聽 聽 聽 productsInCart聽 聽 聽 }}聽 聽 >聽 聽 聽 {children}聽 聽 </AppContext.Provider>聽 );}`

    Env茅s de un contador se le pueden pasar los datos del producto que fue agregado al carrito y hacer el contador con .length (una propiedad que retorna el n煤mero de elementos de un Array) de esta manera ya incluso se podr铆an mostrar los productos en el carrito

    // Contexto
    import { createContext, useState } from "react";
    export const CartContext = createContext()
    export const CartProvider = ({ children }) => {
        const [cart, setCart] = useState([])
        const addToCart = (product) => {
            setCart(prevState => ([
                ...prevState,
                {
                    ...product
                }
            ]
            ))
        }
       
        return (
            <CartContext.Provider value={{
                cart,
                addToCart
            }} >
                {children}
            </CartContext.Provider >)
    }
    
    // A帽adir producto al carrito. componente Card 
    
    import { CartContext } from "../../Context/Cart"
    import { useContext } from "react";
    
    export function Card({ price, title, category, image, id }) {
        const { addToCart, cart } = useContext(CartContext);
        const checkProductInCart = (product) => {
            return cart.some(item => item.id === product.id)
        }
        const isProductInCart = checkProductInCart({ id })
        return (
            <article className='cursor-pointer w-56 h-60 rounded-lg p-4'>
                <figure className='relative mb-2 w-full h-4/5'>
                    <figcaption className='absolute bottom-0 left-0 bg-white/60 rounded-lg text-black text-xs m-2 px-3 py-0.5'>
                        {category}
                    </figcaption>
                    <img className='w-full h-full object-cover rounded-lg' src={image} alt={title} />
                    <button className='absolute top-0 right-0 flex justify-center items-center bg-white w-6 h-6 rounded-full m-2 p-1 text-black'
                        onClick={() => addToCart({ price, title, category, image, id })}  >
                        {isProductInCart ? 'x' : '+'}
                    </button>
                </figure><p className='flex justify-between'>
                    <span className='text-sm font-light'>{title}</span>
                    <span className='text-lg font-medium'>{price}</span></p>
            </article>
        )
    }
    
    Mostrar Cantidad de productos en el NavBar
    
    import { NavLink } from 'react-router-dom'
    import { categories } from '../../Services/products'
    import { useContext } from 'react';
    import { CartContext } from '../../Context/Cart';
    export const Navbar = () => {
        const { cart } = useContext(CartContext);
    
        return (
            <nav className='flex justify-between items-center bg-white dark:bg-zinc-900 fixed z-10 w-full py-5 px-8 text-sm font-light top-0'>
                <ul className='flex items-center gap-3'>
                    <li>
                        馃洅 {cart.length}
                    </li>
                </ul>
            </nav>
        )
    }
    
    
    Asi va quedando el mio: ![](https://static.platzi.com/media/user_upload/image-4dc4640f-6496-4819-a178-ea6c69cc3dbc.jpg)
    Mi dise帽o: ![](https://static.platzi.com/media/user_upload/image-37fa1b83-7253-42c7-9ad9-08be59bd4a9f.jpg)
    Le agregue un par de cositas, el carousel modifique un poco las card, agregue algo de color y tambi茅n la respuesta responsive, al final del curso dejare el enlace del repo y del git page para que vayan a visitarlo <3 ajajajja ![](https://i.ibb.co/tPC1pqD/Captura-de-pantalla-2023-10-01-175036.png)

    Por buenas pr谩cticas en react se recomienda usar una arro function que actualiza el estado dentro del setState en lugar de actualizar el estado con operaciones simples directas porque si es que hay m谩s de un setState en el mismo archivo el valor real del estado se perder谩 y solo reflejara el resultado del primer setState. En otras palabras se debe usar el setState de esta manera鈥

    <div className='absolute top-0 right-0 flex justify-center items-center bg-white w-6 h-6 rounded-full m-2 p-1' onClick={()=>(context.setCount(***(count)=>count+1***))}>+</div>
    

    Y no de esta manera鈥

    <div className='absolute top-0 right-0 flex justify-center items-center bg-white w-6 h-6 rounded-full m-2 p-1' onClick={()=>(context.setCount(context.count + 1))}>+</div> 
    

    Fuente:

    Alguien me podr铆a indicar por que a la hora de agregar un item me sale el mismo mensaje dos veces

    Yo quise que se le diera un feedback al usuario al agregar productos al carrito, para ello agrege un operador ternario que al momento de validar que el count es mayor que 0 agregara unas clases al elemento para que se visualize mejor.

    <li>
    	<span>馃挵</span>
            <span 
    		className={count == 0 ? '' : 'bg-blue-500 rounded-full text-white px-2 py-0.5 font-semibold'}
    	>
    		{count}
    	</span>
    </li>
    

    Asi vamos鈥

    Para los que lo hicimos con un array se me ocurrio esta manera de agregar el contador 馃槃

    Mis apuntes:

    tomamos el context de react, ese context lo pasamos a una variable que se termina leyendo en un componente.

    import { createContext, useState } from 鈥榬eact鈥

    export const ShoppingCartContext = createContext()

    export const ShoppingCartProvider = ({children}) => {

    const [count, setCount] = useState(0) // establecemos un contador inicial, y una variable que acepte los cambios en el contador
    
    
    return (
        <ShoppingCartContext.Provider value={{
            count,
            setCount
        }}>
            {children}
        </ShoppingCartContext.Provider>
    )
    

    }

    Para hacer uso del contexto, pasamos el contexto declarado a una variable en otro componente y llamamos al componente con una funci贸n:
    
      <li>
                    馃洅 {context.count}
                </li>
    

    o

    import {ShoppingCartContext } from 鈥樷/鈥/Context鈥

    const Card = (data) => {

    const context = useContext(ShoppingCartContext) // lee el estado global del proveedor
    

    //鈥//
    <div
    onClick={() => context.setCount(context.count + 1)}
    >
    +
    </div>

    }

    Hola, estoy super contenta con este curso, porque he comprendido mas a profundidas los conceptos adquiridos con el profe Juan DC ()

    para los que estan usando exports nombrados, deben exportar 2 cosas

    export { ShoppingCartProvider, ShoppingCartContext }

    por aca les dejo el Store con Zustand por si no quieren usar Context, automaticamente guarda en localStorage la suma, se puede modificar para que no guarde numeros si no que el objeto a帽adido solo modifiquen la suma y el type o interface

    Creo que lo que m谩s me ha gustado de este curso es lo sencillo que lo hace la profe teff. Si necesitas conocimientos previos tal como lo dijeron al inicio del curso

    As铆 va mi proyecto!!!

    Card component

    import { useContext } from 'react'
    import { ShoppingCartContext } from '../../context'
    
    const Card = ({ product }) => {
      const { count, setCount } = useContext(ShoppingCartContext)
      const { category, images, title, price } = product
    
      const handleClick = () => {
        setCount(count + 1)
      }
    
      return (
        <div className="bg-white cursor-pointer w-56 h-60 rounded-lg">
          <figure className="relative mb-2 w-full h-4/5">
            <span className="absolute bottom-0 left-0 bg-white/60 rounded-lg text-black text-xs m-2 px-3 py-0.5">
              {category.name}
            </span>
            <img className="w-full h-full object-cover rounded-lg" src={images[0]} alt={title} />
            <div
              className="absolute top-0 right-0 flex justify-center items-center bg-white w-6 h-6 rounded-full m-2  p-1"
              onClick={handleClick}
            >
              +
            </div>
          </figure>
          <p className="flex justify-between">
            <span className="text-sm font-light">{title}</span>
            <span className="text-lg font-medium">${price}</span>
          </p>
        </div>
      )
    }
    
    export default Card
    
    
    mi aporte en TS: ![](https://static.platzi.com/media/user_upload/carbon%20%285%29-c52be841-38b0-4633-9b76-f1a1d6e877a5.jpg)
    as铆 voy pero tengo problemas con el API ![](https://static.platzi.com/media/user_upload/imagen-95535f43-343b-4f75-8011-b7f80231037f.jpg)