Home > Software design >  Why UI components don't update when user presses buttons in React?
Why UI components don't update when user presses buttons in React?

Time:10-17

I am building a project and stacked. I am trying to implement a function which has to filter products by category and sort it in UI when user presses category button, so when I press button the array is updated but UI component does not work and I always have the same products. What I am doing wrong here? Here is my code:

import React, { useState, useEffect } from "react";
import "./ItemComponent.css";

function ItemsComponent() {
  const [items, setItems] = useState([]);
  const [search, setSearch] = useState("");
  const [filterItems, setFilterItems] = useState(items);

  // Fetching Data
  useEffect(() => {
    const fetchedData = async () => {
      try {
        const response = await fetch(`https://fakestoreapi.com/products`);
        const data = await response.json();
        console.log("Data", data);
        setItems(data);
      } catch (error) {
        console.log(error);
      }
    };
    fetchedData();
  }, []);

  const handleSubmit = (e) => {
    e.preventDefault();
  };

  const filterProduct = (cat) => {
    const updatedList = items.filter((item) => item.category === cat);
    console.log("cat", cat);
    console.log("updated", updatedList);
    setFilterItems(updatedList);
  };

  return (
    <>
      <header>
        <div className="overlay">
          <h2>Welcome To E-Commerce Shop</h2>
        </div>
        <div className="search">
          <form onSubmit={handleSubmit}>
            <input
              type="text"
              placeholder="Search..."
              onChange={(e) => setSearch(e.target.value)}
            />
            <button className="btn-light btn-search">Search</button>
          </form>
        </div>
        <div className="categories">
          <button
            className="btn-dark category"
            onClick={() => setFilterItems(items)}
          >
            All
          </button>
          <button
            className="btn-dark category"
            onClick={() => filterProduct("men's clothing")}
          >
            Men's Clothing
          </button>
          <button
            className="btn-dark category"
            onClick={() => filterProduct("women's clothing")}
          >
            Women's Closing
          </button>
          <button
            className="btn-dark category"
            onClick={() => filterProduct("jewelery")}
          >
            Jewelry
          </button>
          <button
            className="btn-dark category"
            onClick={() => filterProduct("electronics")}
          >
            Electronics
          </button>
        </div>
      </header>
      <div className="display-grid">
        {Array.from(items)
          .filter((value) => {
            if (search === "") {
              return value;
            } else if (
              value.title.toLowerCase().includes(search.toLowerCase())
            ) {
              return value;
            }
          })
          .map((item) => (
            <div key={item.id}>
              <div className="card">
                <p className="title">{item.title}</p>
                <img src={item.image} />
                {/* <p className="description">{item.description}</p> */}
                <p className="price">£ {item.price}</p>
                <button className="btn-dark btn-buy">
                  <a href="#" className="btn-link">
                    Buy Now
                  </a>
                </button>
              </div>
            </div>
          ))}
      </div>
    </>
  );
}

export default ItemsComponent;

Here is I added screenshot to be more clear. enter image description hereThank you in advance.

CodePudding user response:

You're not using your filterItems array. You can fix it by using it in your display-grid mapping:

     <div className="display-grid">
        {Array.from(filterItems)
          .filter((value) => {
            if (search === "") {
              return value;
            } else if (
              value.title.toLowerCase().includes(search.toLowerCase())
            ) {
              return value;
            }
          })
          .map((item) => (
            <div key={item.id}>
              <div className="card">
                <p className="title">{item.title}</p>
                <img src={item.image} />
                {/* <p className="description">{item.description}</p> */}
                <p className="price">£ {item.price}</p>
                <button className="btn-dark btn-buy">
                  <a href="#" className="btn-link">
                    Buy Now
                  </a>
                </button>
              </div>
            </div>
          ))}
      </div>

However, you might make things a bit more clear when you save your filter inside a state, instead of the filtered array created from the handler. You can then filter and search in one go as such:

const filterProduct = (cat) => setFilter(cat);

{Array.from(items).filter(item => !filter || item.category === filter)
          .filter((value) => !search || value.title.toLowerCase().includes(search.toLowerCase()))
          .map((item) => (
            <div key={item.id}>
              <div className="card">
                <p className="title">{item.title}</p>
                <img src={item.image} />
                {/* <p className="description">{item.description}</p> */}
                <p className="price">£ {item.price}</p>
                <button className="btn-dark btn-buy">
                  <a href="#" className="btn-link">
                    Buy Now
                  </a>
                </button>
              </div>
            </div>
          ))}

Here's a sandbox for it: https://codesandbox.io/s/elated-bartik-hq0cs7?file=/src/App.js

CodePudding user response:

in your arrow function "filterProduct" your are changing the "filterItems" with "setFilterItems" but in you are rendering your ui with "items" state.

Try to use "filterItems" to render your data

  • Related