Search code examples
reactjsuse-effectuse-state

How to filter Products in React.js?


I am fetching local data through json server. db.json is attached for your reference. When I search any text I want to filter products using heading and when I click on filter checkbox then also I want to filter products by category, size and packs. I have attached every component below for your reference which I am using in this project. Please help me I am using BOOTSTRAP 4.6.0 as UI.

CHECK CODESANDBOX LINK - https://xo6b9.codesandbox.io/product-listing FOR BETTER UNDERSTANDING.

PRODUCT LISTING COMPONENT

import React, { useState, useEffect } from "react";
import PageNotFound from "../other/PageNotFound";
import Loading from "../other/Loading";
import ProductView from "./ProductView";
import SearchResult from "./SearchResult";
import Filter from "./Filter";

const ProductsListing = () => {
  const [loading, setLoading] = useState(true);
  const [products, setProducts] = useState([]);
  const [filters, setFilters] = useState([]);
  const [typedValue, setTypedValue] = useState("");

  useEffect(() => {
    getProductListingData();
  }, []);

  const getProductListingData = async () => {
    try {
      const response = await fetch("http://localhost:8000/productListing");
      const data = await response.json();
      if (data) {
        setLoading(false);
        setProducts(data.products);
        setFilters(data.filters);
      } else {
        setProducts("PRODUCT LISTING DATA NOT FOUND");
      }
    } catch (error) {
      console.log(error);
    }
  };

  if (loading) {
    return <Loading loadingProductListing="Loading Product List" />;
  }

  const searchFilterFunction = (e) => {
    setTypedValue(e);
    console.log(typedValue);
    if (typedValue !== "") {
      const newArray = products.filter((item) => {
        return item.heading.indexOf(typedValue) > -1;
      });
      console.log(newArray);
      setProducts(newArray);
    } else {
      console.log("else block");
      setProducts(products);
    }
  };

  return (
    <>
      {products && filters ? (
        <section className="dvMain">
          <div className="container-fluid">
            <div className="row">
              <Filter filters={filters} />
              <div className="dvProducts col-lg-6 col-xl-8">
                <div className="row">
                  <SearchResult
                    searchFilterFunction={(e) => searchFilterFunction(e)}
                  />
                  <div className="dvFilterMobile col-sm-3 col-md-2 d-lg-none text-center text-sm-right mb-3">
                    <a
                      href=""
                      className="btn bg-light w-100"
                      data-toggle="modal"
                      data-target="#mobileFiltersModal"
                    >
                      <i className="fa fa-filter"></i>Filter
                    </a>
                  </div>
                </div>
                <ProductView products={products} />
              </div>
              <div className="dvCart col-lg-3 col-xl-2 d-none d-lg-block">
                <div className="sticky-top" style={{ top: "100px" }}>
                  <div className="row">
                    <div className="col-sm-12 mb-2">
                      <h5 className="d-inline-block">Cart</h5>
                      <span className="d-inline-block">106 items</span>
                    </div>
                    <div className="dvCartItems col-sm-12 mb-2">
                      <div className="row">
                        <div className="scrollbar mr-3">
                          <div className="item col-sm-12 mb-2 pr-0">
                            <div className="bg-light pt-2 pb-2">
                              <div className="col-12">
                                <h6>Pomegranate</h6>
                                <p className="f10 text-muted mb-1">250ml</p>
                              </div>
                              <div className="col-sm-12">
                                <div className="d-flex justify-content-between align-items-center">
                                  <div className="addBtn d-flex justify-content-center align-items-center flex-1">
                                    <div className="flex-1 text-center">
                                      <i className="fa fa-minus"></i>
                                    </div>
                                    <div className="flex-3 text-center">
                                      <input
                                        type="text"
                                        className="form-control text-center p-0"
                                      />
                                    </div>
                                    <div className="flex-1 text-center">
                                      <i className="fa fa-plus"></i>
                                    </div>
                                  </div>
                                  <div className="text-right">
                                    <i className="fa fa-inr"></i>600
                                  </div>
                                </div>
                              </div>
                              <button className="btn btnRemove absolute">
                                <i className="fa fa-close"></i>
                              </button>
                            </div>
                          </div>
                          <div className="item col-sm-12 mb-2 pr-0">
                            <div className="bg-light pt-2 pb-2">
                              <div className="col-12">
                                <h6>Coconut Water</h6>
                                <p className="f10 text-muted mb-1">200ml</p>
                              </div>
                              <div className="col-sm-12">
                                <div className="d-flex justify-content-between align-items-center">
                                  <div className="addBtn d-flex justify-content-center align-items-center flex-1">
                                    <div className="flex-1 text-center">
                                      <i className="fa fa-minus"></i>
                                    </div>
                                    <div className="flex-3 text-center">
                                      <input
                                        type="text"
                                        className="form-control text-center p-0"
                                      />
                                    </div>
                                    <div className="flex-1 text-center">
                                      <i className="fa fa-plus"></i>
                                    </div>
                                  </div>
                                  <div className="text-right">
                                    <i className="fa fa-inr"></i>80
                                  </div>
                                </div>
                              </div>
                              <button className="btn btnRemove absolute">
                                <i className="fa fa-close"></i>
                              </button>
                            </div>
                          </div>
                          <div className="item col-sm-12 mb-2 pr-0">
                            <div className="bg-light pt-2 pb-2">
                              <div className="col-12">
                                <h6>Mango</h6>
                                <p className="f10 text-muted mb-1">200ml</p>
                              </div>
                              <div className="col-sm-12">
                                <div className="d-flex justify-content-between align-items-center">
                                  <div className="addBtn d-flex justify-content-center align-items-center flex-1">
                                    <div className="flex-1 text-center">
                                      <i className="fa fa-minus"></i>
                                    </div>
                                    <div className="flex-3 text-center">
                                      <input
                                        type="text"
                                        className="form-control text-center p-0"
                                      />
                                    </div>
                                    <div className="flex-1 text-center">
                                      <i className="fa fa-plus"></i>
                                    </div>
                                  </div>
                                  <div className="text-right">
                                    <i className="fa fa-inr"></i>48
                                  </div>
                                </div>
                              </div>
                              <button className="btn btnRemove absolute">
                                <i className="fa fa-close"></i>
                              </button>
                            </div>
                          </div>
                          <div className="item col-sm-12 mb-2 pr-0">
                            <div className="bg-light pt-2 pb-2">
                              <div className="col-12">
                                <h6>Sugarcane</h6>
                                <p className="f10 text-muted mb-1">250ml</p>
                              </div>
                              <div className="col-sm-12">
                                <div className="d-flex justify-content-between align-items-center">
                                  <div className="addBtn d-flex justify-content-center align-items-center flex-1">
                                    <div className="flex-1 text-center">
                                      <i className="fa fa-minus"></i>
                                    </div>
                                    <div className="flex-3 text-center">
                                      <input
                                        type="text"
                                        className="form-control text-center p-0"
                                      />
                                    </div>
                                    <div className="flex-1 text-center">
                                      <i className="fa fa-plus"></i>
                                    </div>
                                  </div>
                                  <div className="text-right">
                                    <i className="fa fa-inr"></i>64
                                  </div>
                                </div>
                              </div>
                              <button className="btn btnRemove absolute">
                                <i className="fa fa-close"></i>
                              </button>
                            </div>
                          </div>
                          <div className="item col-sm-12 mb-2 pr-0">
                            <div className="bg-light pt-2 pb-2">
                              <div className="col-12">
                                <h6>Life</h6>
                                <p className="f10 text-muted mb-1">250ml</p>
                              </div>
                              <div className="col-sm-12">
                                <div className="d-flex justify-content-between align-items-center">
                                  <div className="addBtn d-flex justify-content-center align-items-center flex-1">
                                    <div className="flex-1 text-center">
                                      <i className="fa fa-minus"></i>
                                    </div>
                                    <div className="flex-3 text-center">
                                      <input
                                        type="text"
                                        className="form-control text-center p-0"
                                      />
                                    </div>
                                    <div className="flex-1 text-center">
                                      <i className="fa fa-plus"></i>
                                    </div>
                                  </div>
                                  <div className="text-right">
                                    <i className="fa fa-inr"></i>120
                                  </div>
                                </div>
                              </div>
                              <button className="btn btnRemove absolute">
                                <i className="fa fa-close"></i>
                              </button>
                            </div>
                          </div>
                          <div className="item col-sm-12 mb-2 pr-0">
                            <div className="bg-light pt-2 pb-2">
                              <div className="col-12">
                                <h6>Valencia Orange</h6>
                                <p className="f10 text-muted mb-1">1litre</p>
                              </div>
                              <div className="col-sm-12">
                                <div className="d-flex justify-content-between align-items-center">
                                  <div className="addBtn d-flex justify-content-center align-items-center flex-1">
                                    <div className="flex-1 text-center">
                                      <i className="fa fa-minus"></i>
                                    </div>
                                    <div className="flex-3 text-center">
                                      <input
                                        type="text"
                                        className="form-control text-center p-0"
                                      />
                                    </div>
                                    <div className="flex-1 text-center">
                                      <i className="fa fa-plus"></i>
                                    </div>
                                  </div>
                                  <div className="text-right">
                                    <i className="fa fa-inr"></i>240
                                  </div>
                                </div>
                              </div>
                              <button className="btn btnRemove absolute">
                                <i className="fa fa-close"></i>
                              </button>
                            </div>
                          </div>
                          <div className="item col-sm-12 mb-2 pr-0">
                            <div className="bg-light pt-2 pb-2">
                              <div className="col-12">
                                <h6>Trim</h6>
                                <p className="f10 text-muted mb-1">250ml</p>
                              </div>
                              <div className="col-sm-12">
                                <div className="d-flex justify-content-between align-items-center">
                                  <div className="addBtn d-flex justify-content-center align-items-center flex-1">
                                    <div className="flex-1 text-center">
                                      <i className="fa fa-minus"></i>
                                    </div>
                                    <div className="flex-3 text-center">
                                      <input
                                        type="text"
                                        className="form-control text-center p-0"
                                      />
                                    </div>
                                    <div className="flex-1 text-center">
                                      <i className="fa fa-plus"></i>
                                    </div>
                                  </div>
                                  <div className="text-right">
                                    <i className="fa fa-inr"></i>120
                                  </div>
                                </div>
                              </div>
                              <button className="btn btnRemove absolute">
                                <i className="fa fa-close"></i>
                              </button>
                            </div>
                          </div>
                          <div className="item col-sm-12 mb-2 pr-0">
                            <div className="bg-light pt-2 pb-2">
                              <div className="col-12">
                                <h6>Aloe Lemonade</h6>
                                <p className="f10 text-muted mb-1">250ml</p>
                              </div>
                              <div className="col-sm-12">
                                <div className="d-flex justify-content-between align-items-center">
                                  <div className="addBtn d-flex justify-content-center align-items-center flex-1">
                                    <div className="flex-1 text-center">
                                      <i className="fa fa-minus"></i>
                                    </div>
                                    <div className="flex-3 text-center">
                                      <input
                                        type="text"
                                        className="form-control text-center p-0"
                                      />
                                    </div>
                                    <div className="flex-1 text-center">
                                      <i className="fa fa-plus"></i>
                                    </div>
                                  </div>
                                  <div className="text-right">
                                    <i className="fa fa-inr"></i>40
                                  </div>
                                </div>
                              </div>
                              <button className="btn btnRemove absolute">
                                <i className="fa fa-close"></i>
                              </button>
                            </div>
                          </div>
                        </div>
                      </div>
                    </div>
                    <div className="dvCartEmpty col-12 d-none">
                      <h6>Cart is Empty.</h6>
                      <p className="f12">
                        All Good No Bad! Go ahead, order some items from the
                        menu.
                      </p>
                      <img
                        src="images/cart-empty.png"
                        className="img-fluid"
                        width="200"
                        alt=""
                      />
                    </div>
                    <div className="col-sm-12 mb-2">
                      <div className="d-flex justify-content-between">
                        <div>
                          <h6>Subtotal</h6>
                        </div>
                        <div>
                          <p>
                            <i className="fa fa-inr"></i>1,312.00
                          </p>
                        </div>
                      </div>
                      <p className="f12">Extra charges may apply.</p>
                    </div>
                    <div className="col-sm-12 mb-2">
                      <a href="checkout.html" className="btn btnPrimary w-100">
                        Proceed
                      </a>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </section>
      ) : (
        <PageNotFound />
      )}
    </>
  );
};

export default ProductsListing;

PRODUCT VIEW COMPONENT

import React from "react";

const ProductView = ({ products }) => {
  return (
    <>
      <div className="dvProductView row">
        {products &&
          products.map((product) => {
            const {
              id,
              heading,
              description,
              detailsTable,
              category,
              img,
              packs,
              price,
              size,
            } = product;
            return (
              <div key={id} className="col-6 col-md-4 col-lg-6 col-xl-3 mb-4">
                <div className="border border-light shadow-sm p-1 h-100">
                  <div>
                    <div className="bg-light text-center pt-2 pb-2 mb-1">
                      <a className="d-inline-block" href="">
                        <img src={img} className="img-fluid" alt={heading} />
                      </a>
                    </div>
                    <h6 className="text-center">{heading}</h6>
                  </div>
                  <div className="d-flex justify-content-between mb-1">
                    <div className="size">
                      <p>{size}</p>
                    </div>
                    <div className="discount-price mr-2">
                      <span>
                        <i className="fa fa-inr"></i>
                        <span>{price}</span>
                      </span>
                    </div>
                  </div>
                  <div className="text-center">
                    <button
                      className="btn btnSecondary w-100"
                      href="detail.html"
                    >
                      Add to Bag
                    </button>
                  </div>
                </div>
              </div>
            );
          })}
      </div>
    </>
  );
};

export default ProductView;

SEARCH RESULT COMPONENT

import React, { useState } from "react";

const SearchResult = ({ searchFilterFunction }) => {
  // console.log(searchFilterFunction);
  // const [searchText, setSearchText] = useState("");
  // console.log(searchText);

  return (
    <>
      <div className="dvSearch col-sm-9 col-md-10 col-lg-12 mb-3">
        <form className="position-relative">
          <input
            // value={searchText}
            onChange={(e) => searchFilterFunction(e.target.value)}
            type="text"
            className="form-control"
            placeholder="Search - orange, mango, etc."
          />
          <button className="btn btnSearch position-absolute">
            <i className="fa fa-search"></i>
          </button>
        </form>
      </div>
    </>
  );
};

export default SearchResult;

FILTER COMPONENT

import React from "react";

const Filter = ({ filters }) => {
  return (
    <>
      <div className="dvFilters col-lg-3 col-xl-2 d-none d-lg-block text-right">
        <div className="sticky-top" style={{ top: "100px" }}>
          {filters.map((item, index) => {
            const { id, heading, submenu } = item;
            return (
              <div key={id} className="dvPackages row">
                <div className="col-sm-12">
                  <h5 className={`${index === 0 ? "" : "mt-3"}`}>{heading}</h5>
                </div>
                {submenu.map((item) => {
                  const { id, name } = item;
                  return (
                    <div key={id} className="col-sm-12">
                      <label className="d-inline-block">
                        <span className="badge badge-light">05</span>
                        <span>{name}</span>
                        <input type="checkbox" />
                      </label>
                    </div>
                  );
                })}
              </div>
            );
          })}
        </div>
      </div>
    </>
  );
};

export default Filter;

DB.JSON

{
  "productListing": {
    "filters": [
      {
        "id": 1,
        "heading": "Packages",
        "submenu": [
          { "id": 1, "name": "Subscriptions" },
          { "id": 2, "name": "Value Packs" }
        ]
      },
      {
        "id": 2,
        "heading": "Categories",
        "submenu": [
          { "id": 1, "name": "Juices" },
          { "id": 2, "name": "Cleanses" },
          { "id": 3, "name": "Almond Milk" },
          { "id": 4, "name": "protein MilkShake" }
        ]
      },
      {
        "id": 3,
        "heading": "Size",
        "submenu": [
          { "id": 1, "name": "200ml" },
          { "id": 2, "name": "250ml" },
          { "id": 3, "name": "410ml" }
        ]
      },
      {
        "id": 4,
        "heading": "Packs",
        "submenu": [
          { "id": 1, "name": "pack of 2" },
          { "id": 2, "name": "pack of 4" },
          { "id": 3, "name": "pack of 6" },
          { "id": 4, "name": "pack of 8" },
          { "id": 5, "name": "pack of 10" },
          { "id": 6, "name": "pack of 12" },
          { "id": 7, "name": "pack of 14" },
          { "id": 8, "name": "pack of 16" },
          { "id": 9, "name": "pack of 18" },
          { "id": 10, "name": "pack of 20" },
          { "id": 11, "name": "pack of 24" },
          { "id": 12, "name": "pack of 30" },
          { "id": 13, "name": "pack of 36" }
        ]
      }
    ],
    "products": [
      {
        "id": 1,
        "description": "Valencia Orange Every athlete’s go to natural energy drink; Coconut Water is a complete win-win for your everyday rehydration needs. #iaminlovewiththecoco!",
        "category": "juices",
        "img": "https://static.wixstatic.com/media/2c0034_5b8e230643ee4b6cbb1ae55088b40d50~mv2.png",
        "heading": "Valencia Orange",
        "size": "250ml",
        "packs": 0,
        "price": 80
      },
      {
        "id": 2,
        "description": "Valencia Orange Every athlete’s go to natural energy drink; Coconut Water is a complete win-win for your everyday rehydration needs. #iaminlovewiththecoco!",
        "category": "juices",
        "img": "https://static.wixstatic.com/media/2c0034_e8d3fce1719f402797ddaaa555c094e4~mv2.png",
        "heading": "Valencia Orange",
        "size": "1litre",
        "packs": 0,
        "price": 240
      },
      {
        "id": 3,
        "description": "Trim Every athlete’s go to natural energy drink; Coconut Water is a complete win-win for your everyday rehydration needs. #iaminlovewiththecoco!",
        "category": "juices",
        "img": "https://static.wixstatic.com/media/2c0034_7534300a0eb04f75b0170b7eb8da71aa~mv2.png",
        "heading": "Trim",
        "size": "250ml",
        "packs": 0,
        "price": 120
      }
    ]
  }
}

Solution

  • IN THE PRODUCT LISTING COMPONENT Create a new state and name it allProducts as below :-

    const [allProducts, setAllProducts] = useState([]);
    

    and pass data from async function :-

    const getProductListingData = async () => {
        try {
          const response = await fetch("http://localhost:8000/productListing");
          const data = await response.json();
          if (data) {
            setLoading(false);
            setProducts(data.products);
    
            //send all the products
            setAllProducts(data.products);
    
            setFilters(data.filters);
          } else {
            setProducts("PRODUCT LISTING DATA NOT FOUND");
          }
        } catch (error) {
          console.log(error);
        }
      };
    

    and then set in else block

    const searchFilterFunction = (e) => {
        const inputValue = e;
        console.log(inputValue);
        if (inputValue !== "") {
          console.log(inputValue);
          const newArray = products.filter((item) => {
            return item.heading.toLowerCase().match(inputValue);
          });
          console.log(inputValue);
          setProducts(newArray);
        } else {
          // set allProducts here
          setProducts(allProducts);
        }
      };