No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Corrigiendo bugs de la aplicación

29/31
Recursos

Aportes 26

Preguntas 2

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Esto no lo han explicado mucho pero al useEffect se le puede enviar un return que sirve para limpiar los estados cuando el componente se desmonta
por ejemplo cuando cambiamos de la ruta del Home a la ruta de MyOrders, se desmonta Home, para monta MyOrders

el useEffect tiene la siguiente estructura

useEffect(() => {
	//codigo que va a ejecutar
    first
  
//funcion que sirve para limpiar cuando el componente es desmontado
    return () => {
      second
    }
//las dependencias del useEffect
  }, [third])

en el caso de la clase y con el codigo de la profesora el useEffect seria

useEffect(() => {
    if (searchByTitle && searchByCategory) setFilteredItems(filterBy('BY_TITLE_AND_CATEGORY', items, searchByTitle, searchByCategory))
    if (searchByTitle && !searchByCategory) setFilteredItems(filterBy('BY_TITLE', items, searchByTitle, searchByCategory))
    if (!searchByTitle && searchByCategory) setFilteredItems(filterBy('BY_CATEGORY', items, searchByTitle, searchByCategory))
    if (!searchByTitle && !searchByCategory) setFilteredItems(filterBy(null, items, searchByTitle, searchByCategory))
    return () => {
      setSearchByTitle(null)
    }
  }, [items, searchByTitle, searchByCategory])

asi se aseguran que el input se limpie al cambiar de ruta, la profe solo lo uso al hace checkout, pero que pasa si entras directamente a myOrders o my account desde la navegacion, el input se mantendra, aunque eso pertenece a la logica de negocio, a lo mejor si se quiere que funcione asi el codigo, igual espero que les sirva este aporte

En lo personal siento que se tomo el camino más largo para filtrar por categorías, esto se soluciona con rutas dinámicas

{ path: '/:category', element: <Home /> }

Capturamos el valor de la categoría de esta forma como lo hicimos para ver las órdenes.

const currentPath = window.location.pathname
  let index = currentPath.substring(currentPath.lastIndexOf('/') + 1);

if(index){
      return(
        filteredItems?.filter(item => item.category === index).map((item)=>(
          <Card key={item.id} {...item}/>))
      );
    }
    else {
      return(
        filteredItems?.map((item) => <Card key={item.id} {...item} />));
    }

Con esto es suficiente para hacer el filtro y adicional a ello si tenemos X cantidad de Categorías va seguir funcionando

Así quedó mi mi versión del proyecto.

Otro bug.

Filtrar por categorías tiene el mismo porblema del Filtrar por título,cuando has seleccionado una y quieres volver a All o todos,no se borra el valor setSearchBy Category.

El único bug que sigo viendo es que si recargas la página en alguna ruta, puede ser, /clothes, /electronics, no va a tomar la categoria porque la categoria la toma con el onClick del nav, esa partecita me gustaria que ayudaran a resolverlaxd
-Yo pensé en una solución que es que cuando se recargue la página siempre inicie en /, la raiz
-otra creo que seria que category se guarde en el local storage, pero depronto da más problemas, si alguien sabe porfa ayudaxd

una solución rapidita y sencilla es poner un value en donde está el input, en mi caso uso searchTerm, pero si ponemos en value como el ejemplo de la profe, searchByTitle, sirve de la misma manera. siempre nos saldrá el valor y podemos borrarlo.

Puede parecer una tonteria pero, en pantallas mas pequeñas, el menu superior tiene posicion fixed y al hacer scroll no es legible y se entremezcla con los productos del e-commerce. Añadiendo un simple background white, queda perfecto.
.
Gracias por el curso, he aprendido mucho y refrescado conceptos

me gusto el curso, el código aun tiene mucho por mejorar, pero ya es cuestión nuestra.
También podríamos agregar el reseteo del count, para que vacíe el carrito una vez que hacemos el checkout: `context.setCount(0)`
## 🦄✨Me gustó bastante como finalizó el proyecto. Con una api que tenga más datos como el número de productos disponibles, proveedor, etc, sería un gran proyecto para portafolio. ![](https://static.platzi.com/media/user_upload/localhost_5173_category_furnitures-e51f401d-79f1-4bfa-9a25-4df13ddc4d3e.jpg)
hola, en mi caso solucione dos cosas. 1. Para evitar que filtrado por titulo se realizara en las rutas en donde no debía lo que hice fue setearlo (o actualizarlo) en `null` cada vez que la ruta cambie, esto lo hice añadiendo en el Home una constante `location = useLocation();` que captura la ruta en la cual nos encontramos, y después añadí un `useEffect(() => context.searchByTitle(null), [location]);` . 2. para lograr que el filtrado por categoría se hiciera incluso cuando no se le da click a las opciones en el navbar (es decir, que se hiciera también cuando se recarga la pagina o cuando se escribe directamente la ruta desde la barra de navegación), lo que hice fue cambier en el componente `AppRoutes` las rutas de las clases anteriores por `{path: /home/categoryProduct, element: <home />}` y en Home agregar `const { categoryProduct } = useParams();` edemas de un `useEffect` que cambie cada vez que cambie `categoryProduct` de la siguiente manera: \~~~   useEffect(() => {    if (categoryProduct?.length > 0) {      context.setCurrentCategory(categoryProduct.toLocaleLowerCase());    }  }, \[categoryProduct]); ~~~ acá dejo el código de los componentes de Home y App con los cambios que hice. ## Home: ```js import { useContext, useEffect } from "react"; import { useLocation, useParams } from "react-router-dom"; import { ShoppingCartContext } from "../../context"; import Layout from "../../components/Layuot"; import Card from "../../components/Card"; import ProductDetail from "../../components/ProductDetail"; import CheckoutSideMenu from "../../components/CheckoutSideMenu"; import { FaceFrownIcon } from "@heroicons/react/24/outline"; function Home() { const location = useLocation(); const context = useContext(ShoppingCartContext); const { categoryProduct } = useParams(); const renderView = () => { const itemsToRender = context.searchByTitle?.length > 0 || context.currentCategory?.length > 0 ? context.filteredItems : context.items; if (itemsToRender?.length > 0) { return itemsToRender.map((item) => <Card key={item.id} data={item} />); } else { return (
<FaceFrownIcon className="m-2 size-20" />

{"Sorry, we can't find your product"}

); } }; useEffect(() => { if (categoryProduct?.length > 0) { context.setCurrentCategory(categoryProduct.toLocaleLowerCase()); } }, [categoryProduct]); useEffect(() => { context.setSearchByTitle(null); }, [location]); return ( <Layout>
<h1 className="text-center text-lg font-medium">Our Products <input type="text" placeholder="find your products" className="mb-2 p-2 w-72 text-center text-sm border border-black rounded-lg focus:outline-none focus:shadow-lg" onChange={(e) => context.setSearchByTitle(e.target.value)} />
{renderView()}
<ProductDetail /> <CheckoutSideMenu /> </Layout> ); } export default Home; ``` ## App: ```js import { useRoutes, BrowserRouter } from "react-router-dom"; import { ShoppingCartProvider } from "../../context"; import Home from "../Home"; import MyAccount from "../Myaccount"; import MyOrder from "../MyOrder"; import MyOrders from "../MyOrders"; import NotFound from "../NotFound"; import SignIn from "../SignIn"; import Navbar from "../../components/Navbar"; import "./App.css"; const AppRoutes = () => { let routes = useRoutes([ { path: "/", element: <Home />, }, { path: "/home/:categoryProduct", element: <Home />, }, { path: "/my-account", element: <MyAccount />, }, { path: "/my-order", element: <MyOrder />, }, { path: "/my-orders", element: <MyOrders />, }, { path: "/my-orders/last", element: <MyOrder />, }, { path: "/my-orders/:id", element: <MyOrder />, }, { path: "/sign-in", element: <SignIn />, }, { path: "/*", element: <NotFound />, }, ]); return routes; }; function App() { return ( <ShoppingCartProvider> <BrowserRouter> <AppRoutes /> <Navbar /> </BrowserRouter> </ShoppingCartProvider> ); } export default App; ```Espero que mi aporte les sirva 😊.
me ha costado el ruteo

Para hacer la ruta de forma dinamica podemos usar el hook useParams, de la siguiente forma:

En las rutas:

{ path: '/:category', element: <Home /> },

En el Home

const { category } = useParams()

  useEffect(() => {
    if (category?.length > 0) context.setSearchByCategory(category.toLowerCase())
  }, [category])

De esta forma no tenemos que depender de ese onClick y tenemos acceso a las categorias por medio de la url

No se si esta bien hacerlo asi, pero yo me ahorre bastante codigo y siendo que queda menos confuso y automatizado quizas. Les dejo mi codigo para ver que puedo mejorar. ```js function Home() { const { items, searchByTitle, setSearchByTitle, filteredItems } = useContext(ShoppingCartContext) // If you want to insert a category, do it in pathAndCategory with its respective path. Category filtering does not have a state; it filters using the existing items using the values inserted in pathAndCategory. const pathAndCategories = { "/clothes": "clothing", "/electronics": "electronics", "/jewelerys": "jewelery" } const renderSearch = (items) => { if (items?.length > 0) { return ( items?.map((item) => ( <Card key={item.id} data={item} /> )) ) } else { return (
No products found matching your search. Please try again with different terms.
) } } const renderView = (categories) => { const areInHome = window.location.pathname === "/" const existSearch = searchByTitle?.length > 0; //In Home if (areInHome) { if (existSearch) { return ( renderSearch(filteredItems) ) } return ( items?.map((item) => ( <Card key={item.id} data={item} /> )) ) } //In Categories if (!areInHome) { //Utils let categoryOfThePath = categories[window.location.pathname]; let itemsFilterByPath = items?.filter(item => item.category.includes(categoryOfThePath)); if (searchByTitle?.length === 0) { return ( itemsFilterByPath?.map((item) => ( <Card key={item.id} data={item} /> )) ) } if (existSearch) { return ( renderSearch(filteredItems?.filter(item => item.category.includes(categoryOfThePath))) ) //Only returns items that meet the corresponding category. } } } ```
Para tener las categorias de manera dinamica ya que pueden cambiar en el futuro opte por  useEffect(() => {    fetch("https://api.escuelajs.co/api/v1/products")      .then((response) => response.json())      .then((data) => {        const categorias = \[...new Set(data.map((item) => item.category.name))];        setItemsCategorys(categorias);        return setItems(data);      });  }, \[]); ```js useEffect(() => { fetch("https://api.escuelajs.co/api/v1/products") .then((response) => response.json()) .then((data) => { const categorias = [...new Set(data.map((item) => item.category.name))]; setItemsCategorys(categorias); return setItems(data); }); }, []); ```y ya salo tengo que llamar las categorías en el navbar

Yo le adicione algo mas a mi aplicación

No sé si se dieron cuenta pero al inicio por unos milisegundos mientras se recarga la página aparece el mensaje de Not Found o No se encontraron productos (como le hayan puesto), para quitar ese mensaje cree un estado en el Context de carga como te muestro a continuacion

  // Initial page load
  const [isLoading, setIsLoading] = useState(true);

Luego de esto en el fetch setie (actualicé) mi estado de la siguiente manera

 useEffect(() => {
    setIsLoading(true); //start charging
    fetch("https://fakestoreapi.com/products")
      .then((response) => response.json())
      .then((data) => {
        setItems(data);
        setIsLoading(false); // charging ends
      })
      .catch((error) => {
        console.error("Error fetching data: ", error);
        setIsLoading(false);
      });
  }, []);

Le envie estado de isLoading a mi Provider

Acto siguiente en mi pagina de Home que donde se renderizan mis Cards incluí el siguiente condicional

 const renderView = () => {
    if (context.isLoading) {
      return <div>Loading...</div>; // Este condicional hace que me aparezca un mensajito de Loading... al inicio
    }
    if (context.filteredItems?.length > 0) {
      return context.filteredItems?.map((item) => (
        <Card key={item.id} data={item} />
      ));
    } else {
      return <div className=" text-gray-400 text-xl">Product Not Found</div>;
    }
  };

Y listo!!

Para lo del input de búsqueda, creo que es bueno poner el context.searchByCategory en el input para que cuando cambie de página siempre se ponga de nuevo el valor que se tenía y no genere confusión, lo deje así: ` <input` ` type="text"` ` value={context.searchByTitle}` ` className="border border-gray-800 rounded-lg mb-4 py-3 focus:outline-none px-5"` ` placeholder="Search products by name"` ` onChange={(event) => {` ` context.setSearchByTitle(event.target.value);` ` }}` ` />`
así itero los elementos, el operador `? lo `use para el encadenamiento opcional, lo que ayuda a evitar errores si las propiedades como `product.title`, `product.category` son nulas o indefinidas. ![](https://static.platzi.com/media/user_upload/filtrarpor%20titulo%20o%20categoria-102fbe63-2f57-4226-8197-565074a66d8d.jpg)
Así lo filtre ,use una función y dentro de ella hago el filtro por titulo o categoría, y retorno ambos resultados ![](https://static.platzi.com/media/user_upload/filtrarpor%20titulo%20o%20categoria-e5d7ede9-d131-4523-a9f3-b857db813212.jpg)
Nadie ha dicho que en el useEffect falta agregar la dependencia de filterBy (ESLint no me dejaba en paz si no la ponía) la puse y oh sorpresa me aparecía este warning y el contador subía como loco cada vez hacía filtrado x titulo o categoría (creí q este era el bug q iban a solucionar en la clase) ![](https://static.platzi.com/media/user_upload/image-484a8e2b-6e1c-4b5c-adf4-a5ba8c8d9a9d.jpg) así que después de investigar, la solución es envolver **filterBy()** en un hook llamado **useCallback** para evitar que se re-renderize al infinito como loco: ![](https://static.platzi.com/media/user_upload/image-492ef9ee-5fa7-4865-bd82-a0af81f61d2e.jpg) espero que esto le sirva a alguien si se topa con el mismo problema, fuente: <https://dev.to/amitaldo/function-makes-the-dependencies-of-useeffect-hook-change-on-every-render-warning-in-react-35hd>
Succesfull
Yo lo hice de esta manera, me parece menos profesional pero mas concreta![](https://imgur.com/a/TWUlkjw)
Así realice yo mi renderView ```js const renderView = () => { const products = filteredItems ?? items; if (products?.length > 0) { return products?.map((item) => <Card key={item.id} data={item} />); } else { return
No products founds
; } }; ``` const renderView = () => { const products = filteredItems ?? items; if (products?.length > 0) { return products?.map((*item*) => \<Card *key*={*item*.id} *data*={*item*} />); } else { return \
No products founds\
; } };

Casi muesro buscando el problema ya lo habia notado clases atras y lo estaba intentando solucionar, esta clase me ayudo mucho 😃

Una forma de evitar el error de que en el input se almacene el valor aunque no se colocaba/veía nada en el input es colocandole el atributo value así:

Los filtros lo hice de diferente manera, podrían analizar el codigo en: https://github.com/Eddy-Huaylla/platzi-curso-react-vite-tailwind-css/tree/a9d92bc2aa3dbfcafc2f729262119dcde9657662

Saludos.