Search code examples
reactjsinfinite-scroll

reset new array reactjs infinite scroll


I have tried infinite scroll for reactjs from this link https://www.youtube.com/watch?v=NZKUirTtxcg&t=303 and work perfectly. But I want to improve with my condition.

I have make infite scroll for case products, the product has sub_category and sub_category has one category. For example I have one page showing all products by category (it's showing all sub_category).

The user can choose the product base sub_category (the page showing just what user choose for sub_category).

And my problem is I don't know to reset product variable as new array to fullfill products from sub_category.

I have two component ListInfiteTwo.jsx and UseProductSearch.jsx

ListInfiteTwo.jsx

import React, { useEffect, useState, useRef, useCallback } from 'react';
import axios from 'axios';
import { makeStyles } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';

import '../styleProduct.css';
import { NavbarPageListProduct, NotFoundPage, COBottomNav } from '../../../components';
import configAPI from '../../../api/configAPI';
import productAPI from '../../../api/productAPI';
import Kcard from '../../Card/Kcard';
import UseProductSearch from './UseProductSearch';

export default function ListInfiniteTwo(props) {
    const classes = useStyles();
    const [totQtyItem, setTotQtyItem] = useState(null);

    const [pageNumber, setPageNumber] = useState(1);
    const [category, setCategory] = useState(props.match.params.id);
    const [subCategory, setSubCategory] = useState(null);
    const [subCategories, setSubCategories] = useState([]);
    const [amount, setAmount] = useState(0);
    const [limit, setLimit] = useState(6);
    const [selectedSubCategory, setSelectedSubCategory] = useState('selectedSubCategory');

    const {
        loading,
        error,
        products,
        hasMore
    } = UseProductSearch(pageNumber, category, limit, subCategory)

    const observer = useRef()
    const lastProductElementRef = useCallback(node => {
        if (loading) return
        if (observer.current) observer.current.disconnect()
        observer.current = new IntersectionObserver(entries => {
            if (entries[0].isIntersecting && hasMore) {
                setPageNumber(prevPageNumber => prevPageNumber + 1)
            }
        })
        if (node) observer.current.observe(node)
    }, [loading, hasMore])

    useEffect(() => {
        let getSubCategoriesAct = configAPI.getSubCategory(kategori);

        getSubCategoriesAct.then((response) => {            
            setSubCategories(response.data)
        }).catch(error => {
            console.log(error)
        });
    },[])

    const callBackAddItemTotal = (data) => {
        setTotQtyItem(data)
    }

    const callBackDeleteItemTotal = (data) => {
        setTotQtyItem(data)
    }

    const callBackCalculateAmount = (data) => {
        setAmount(data);
    }

    const selectSubCategory = (id) => {
        setSubKategori(id)
        setPageNumber(1)
    }

    return (
        <>
            <NavbarPageListProduct 
                titleView="List Product"
                viewPrev="detailOrder"
                totalQtyItem={totQtyItem}
                cHistoryId={props.match.params.id}
            />
            <div className={classes.root}>
                <div className="css-ovr-auto">
                    <div className="css-ovr-auto">
                        <div className="css-c-1hj8">
                            <div className="css-c-2k3l">
                                {
                                    <>
                                        <div className={ selectedSubCategory === 'selectedSubCategory' ? 'css-sb-sl-top-active' : 'css-sb-sl-top'} >
                                            <div className="css-sb-sl-label">
                                                <span className="css-sb-sl-val"> All on Category </span>
                                            </div>
                                        </div>
                                        {subCategories.map((x, z) =>
                                            <div className="css-sb-sl-top" onClick={() => selectSubCategory(x._id) }>
                                                <div className="css-sb-sl-label">
                                                    <span className="css-sb-sl-val" >{x.name}</span>
                                                </div>
                                            </div>
                                        )}
                                    </>
                                }
                            </div>
                        </div>
                    </div>
                </div>

                <Grid container spacing={1}>
                    <Grid container item xs={12} spacing={1}>
                        {
                            products.length >= 1 ?
                                products.map((pr, index) =>
                                    <React.Fragment>
                                        <div ref={lastProductElementRef}></div>
                                        <Kcard
                                            ref={lastProductElementRef}
                                            product={pr}
                                            callBackAddItemTotal={callBackAddItemTotal}
                                            callBackDeleteItemTotal={callBackDeleteItemTotal}
                                            callBackCalculateAmount={callBackCalculateAmount}
                                        />
                                    </React.Fragment>
                                )
                            :
                                <NotFoundPage 
                                    content="No Products"
                                />
                        }
                    </Grid>
                </Grid>
            </div>
            <div>{loading && 'Loading...'}</div>
            <div>{error && 'Error'}</div>
            {
                amount > 0 ?
                    <COBottomNav 
                        titleBottom="Total Pay"
                        amount={amount}
                        titleBtnBottom="Process"
                        action='proces_list'
                    />
                :
                    ""
            }
        </>
    )
}

UseProductSearch.jsx

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

export default function UseProductSearch(pageNumber, category, limit, subCategory) {
    const [loading, setLoading] = useState(true)
    const [error, setError] = useState(false)
    const [products, setProducts] = useState([])
    const [hasMore, setHasMore] = useState(false)
    const [lastPage, setLastPage] = useState(0)

    useEffect(() => {
        setProducts([])
    }, [])

    useEffect(() => {
        setLoading(true)
        setError(false)
        let cancel

            if (subCategory) {
                setProducts([])
            }

            axios({
                method: 'GET',
                url: process.env.REACT_APP_API_URL + `data-product-pagination`,
                params: {
                    orderby: 'newest',
                    type: 'verify',
                    page: pageNumber,
                    limit: limit,
                    xkategori: category,
                    subkategori: subCategory,
                },
                cancelToken: new axios.CancelToken(c => cancel = c)
            }).then(res => {
                if (res.data.data) {
                    if (res.data.data.data.length > 0) {
                        setProducts(prevProducts => {
                            return [...new Set([...prevProducts, ...res.data.data.data])]
                        })
                    }
                }
                setHasMore(res.data.data.data.length > 0)
                setLoading(false)
                setLastPage(res.data.data.last_page)
            }).catch(e => {
                if (axios.isCancel(e)) return
                    setError(true)
            })
            return () => cancel()

    }, [pageNumber, category, limit, subCategory])

    return { loading, error, products, hasMore }
}

what I have tried to add code on UseProductSearch.jsx

if (subCategory) {
   setProducts([])
}

it's work when user choose sub category the page showing new products base on sub_category, but when I scroll down it's reseting the product to empty array.

Thx, for your help...


Solution

  • Try including subCategory as a dependency in your first useEffect hook from useProductSearch instead. This would reset your array whenever the subCategory state changes.

    useEffect(() => {
        setProducts([])
    }, [subCategory])