skip to Main Content

I am practicing a project using React.js as a front-end framework to display the products. I tried to filter the product by the product_type. When fetch the data, I use slice() to show 3 products on each category then if the products in the category are more than 3, on click "see more" button and it will show 3 more products.

Is it any way to just show another 3 product in specific category? Now when I click the button, each category is loading 3 more products.

Any and all feedback is appreciated. Thanks!

App.js

import { useEffect, useState } from "react";
import axios from "axios";

import "./styles.css";
import Product from "./Product";

export default function App() {
  const [products, setProducts] = useState([]);
  const [productSlice, setProductSlice] = useState(3);

  useEffect(() => {
    axios
      .get("https://www.allbirds.com/products.json?limit=50")
      .then((response) => {
        // All products return as an array of product objects
        const { products } = response.data;

        setProducts(products);
      });
  }, []);


  return (
    <div className="App">
      <div>
        {categories.map((cat, i) => (
          <>
            <div>
              <h5 key={i}>{cat}</h5>

              {products
                .filter((type) => type.product_type === cat)
                .slice(0, productSlice)
                .map((product) => (
                  <Product data={product} />
                ))}
            </div>
            <p>
              Total in {cat} :
              {products.filter((type) => type.product_type === cat).length}
            </p>

            <button
              onClick={() => {
                // console.log("This is",cat);
                products.filter((type) => type.product_type === cat).length >
                  2 && setProductSlice(productSlice + 1);
              }}
            >
              See more
            </button>
          </>
        ))}
      </div>

      
    </div>
  );
}

Products.js

export default function Product({ data }) {
  

  const { images, title, handle } = data;

  return (
    <div key={handle}>
      <h2>{title.split("-")[0]}</h2>
      <div>
        <img src={images[0].src} style={{ width: "100px" }} alt={handle} />
      </div>
    </div>
  );
}

2

Answers


  1. You need a dedicated function that will work with your data as need. This can be on when data first is loaded after fetched from API or when the button is clicked asking for more data.

    It´s recommended you work with this data before passing it to your components. This way, you will have a more readable/cleaner code by applying separation of concerns, instead of doing all that transformation/logic on the component. Try to keep complex code away from buttons, divs, components, etc

    My suggestion:

        
         const [products, setProducts] = useState([]); //will contains the remote data
         const [productSlice, setProductSlice] = useState([]); //will contains the current visible slice
    
         const [sliceStart, setSliceStart] = useState(0);
    
         const pageSize = 3;
    
         const updateSlice = useCallback(() => {
    
              const hasMore = products.length > currentIndex;
    
              if (hasMore) {
    
                  //here we get the copy from products
    
                   const end = sliceStart + pageSize;
                   const nextItems = products.slice(sliceStart, end);
    
                   setProductSlice( old => [...old, ...nextItems]);
               }
         }, [products, sliceStart]);
    
    
         useEffect(() => {
    
            const fetchData = async () => {
                const response = await axios.get("https://www.allbirds.com/products.json?limit=50");
    
                // All products return as an array of product objects
                const { products } = response.data;
    
                setProducts(products);
             }
    
    
             fetchData().catch(err => console.error(err));
    
          }, [updateSlice]);
    
          return (
              <>
    
                  <button
                  onClick={() => setSliceStart(prev => prev + pageSize)}>
                      See more
                </button>
    
              </>
          )
        
    

    hope could help you

    Login or Signup to reply.
  2. Since you want different number of products displayed in different category, so you may define a state productSlices to represent those product counts.

    The initial value of productSlices will be

    {
      Shoes: 3,
      Apparel: 3,
      Socks: 3
    }
    

    and for example when you click button in Shoes category, the value of productSlices.Shoes becomes 4 and the rest remain 3. And in the map operation you use productSlices[cat] to get how many products should displayed in the category.

    You can modify your code like this:

    import { useEffect, useState } from "react";
    import axios from "axios";
    
    import "./styles.css";
    import Product from "./Product";
    
    export default function App() {
      const categories = ["Shoes", "Apparel", "Socks"];
      const [products, setProducts] = useState([]);
      
      const [productSlices, setProductSlices] = useState(
        categories.reduce((a, v) => ({ ...a, [v]: 3 }), {})
      );
      
      useEffect(() => {
        axios
          .get("https://www.allbirds.com/products.json?limit=50")
          .then((response) => {
            // All products return as an array of product objects
            const { products } = response.data;
    
            console.log(products);
            setProducts(products);
          });
      }, []);
    
      return (
        <div className="App">
          <div>
            {categories.map((cat, i) => (
              <>
                <div>
                  <h5 key={i}>{cat}</h5>
    
                  {products
                    .filter((type) => type.product_type === cat)
                    .slice(0, productSlices[cat])
                    .map((product) => (
                      <Product data={product} />
                    ))}
                </div>
                <p>
                  Total in {cat} :
                  {products.filter((type) => type.product_type === cat).length}
                </p>
    
                <button
                  id={cat}
                  onClick={() => {
                    setProductSlices({
                      ...productSlices,
                      [cat]: productSlices[cat] + 1
                    });
                  }}
                >
                  See more
                </button>
              </>
            ))}
          </div>
        </div>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search