'React filtering with different urls

I am trying to filter some products by calling a different url based on what the user click in a component. I have a ProductsPage and a FilteredProductsPage component.

My scenario is this: I am on ProductsPage, I click "skin", I see all products from skin category. Now I am on FilteredProductsPage (because the url changed) and I try to click "body" and even though the url changes, the products don't re-render. I see only "skin" cateogory products. These are the Routes in App.js

<Route path='/products' element={<ProductsPage/>}/>
<Route path='/filterProducts/:category/:type' element={<FilteredProductsPage/>}/>

This is the part of code from ProductsPage component where the user click a Link (it's StyledLink but it's based on react-router-dom Link - I used styled components to style it):

<FilterDiv >
          <ArrowForwardIosOutlinedIcon fontSize='small' sx={{color:'#ccc', paddingRight:'20px'}}/>
          <StyledLink to='/filterProducts/skin/all'>all</StyledLink>
          </FilterDiv>
<FilterDiv >
          <ArrowForwardIosOutlinedIcon fontSize='small' sx={{color:'#ccc', paddingRight:'20px'}}/>
          <StyledLink to='/filterProducts/body/all'>all</StyledLink>
          </FilterDiv>

And this is the the whole code from the FilteredProductsPage component (ignore the suggestions part, if from a search bar component). The FilterComponent is the same as the one from ProductsPage which work both for "skin" and "body" if I click them individually

export const FilteredProductsPage = () => {
    const navigate=useNavigate();

    const {category}=useParams();
    const {type}=useParams();

    const [cartItems, setCartItems]=React.useState(0);
    const [user,  error] = useAuthState(auth);

    const [products,setProducts]=React.useState([]);
    const [filteredProducts, setFilteredProducts]=React.useState([]);
    const [loading, setLoading]=React.useState(true);
    const [expanded, setExpanded] = React.useState(false);

    const [searchProducts, setSearchProducts]=React.useState([]);

    const [value, setValue]=React.useState('');
    const [suggestions, setSuggestions]=React.useState('')

    const handleChange = (panel) => (event, isExpanded) => {
        setExpanded(isExpanded ? panel : false);
    };

   
    const fetchProducts=async()=>{
          let searchProductsClone=[];
          
          if(category == 'skin' && type == 'all'){
            let productsClone=[];
            const q = query(collection(db, "products"), where("category", "==", "skin"));
            const querySnapshot=await getDocs(q);
            querySnapshot.forEach((doc) => {
            console.log(doc.id, " => ", doc.data());
            productsClone.push(doc.data())
            let searchProduct={"name": doc.data().name, "brand":doc.data().brand, "img":doc.data().img[0], "uniqueName":doc.data().uniqueName}
            searchProductsClone.push(searchProduct);
  
            console.log(products);
            setLoading(false);
          })
         
            setProducts(productsClone)
          
        }
        else if(category == 'body' && type == 'all'){
            let productsClone=[];
            const q = query(collection(db, "products"), where("category", "==", "body"));
            const querySnapshot=await getDocs(q);
            querySnapshot.forEach((doc) => {
            console.log(doc.id, " => ", doc.data());
            productsClone.push(doc.data())
  
            let searchProduct={"name": doc.data().name, "brand":doc.data().brand, "img":doc.data().img[0], "uniqueName":doc.data().uniqueName}
            searchProductsClone.push(searchProduct);
  
            console.log(products);
            setLoading(false);
          })
       
            setProducts(productsClone)
        
          
        }
          setSearchProducts(searchProductsClone);
  }

  const getSuggestions = value => {
    const inputValue = value.trim().toLowerCase();
    const inputLength = inputValue.length;
  
    return inputLength === 0 ? [] : searchProducts.filter(prod =>
      prod.name.toLowerCase().slice(0, inputLength) === inputValue || prod.brand.toLowerCase().slice(0, inputLength)===inputValue
    );
  };

  const getSuggestionValue = suggestion => suggestion.brand+"-"+suggestion.name;

  const renderSuggestion = suggestion => (
    <div style={{display:'flex', flexDirection:'row', width:'100%'}}>
      <img src={suggestion.img} style={{width:'50px', height:'50px', marginRight:'10px', marginTop:'20px'}}/>
      <p>{suggestion.brand} - {suggestion.name}</p>
    </div>
  );

  const onChange = (event, { newValue }) => {
    setValue(newValue)
  };


  const onSuggestionsFetchRequested = ({ value }) => {
    setSuggestions(getSuggestions(value))
  };


  const onSuggestionsClearRequested = () => {
    setSuggestions(getSuggestions())
  };

  const inputProps = {
    placeholder: 'Search for a product...',
    value,
    onChange: onChange
  };

  const onSuggestionSelected=(event, { suggestion, suggestionValue, suggestionIndex, sectionIndex, method })=>{
          console.log(suggestion)
          navigate('/product/'+suggestion.uniqueName)
  };

  
    const fetchCartItems=async()=>{
    
        const q = query(collection(db, "carts"), where("userUID", "==", user?.uid));
        const docRef = await getDocs(q);
        if(!docRef.empty){
        const currentCartItems=docRef.docs[0].data().cartItems;
        setCartItems(currentCartItems);
        }
   
      }

      React.useEffect(() => {
        fetchCartItems();
        fetchProducts();
        },[], []);
  return (
    <div style={{display:'flex', flexDirection:'column', height:'100%', justifyContent:'center'}}>
    <Navbarr items={cartItems}/>
    <Container>
        <Text>Discover our large selection of products or let us choose for you.</Text>
        <TextSmall>Sustainably-sourced, vegan, organic and cruelty-free. Good for you and good for the planet.</TextSmall>
    </Container>
    <MainProductsContainer>
    
    <FilterContainer>
    {loading == true &&  <Loading background='white'/>}
    <Autosuggest
    theme={theme}
    suggestions={suggestions}
    onSuggestionsFetchRequested={onSuggestionsFetchRequested}
    onSuggestionsClearRequested={onSuggestionsClearRequested}
    onSuggestionSelected={onSuggestionSelected}
    getSuggestionValue={getSuggestionValue}
    renderSuggestion={renderSuggestion}
    inputProps={inputProps}
  />
  <h4>Categories</h4>
    <Accordion expanded={expanded === 'panel1'} onChange={handleChange('panel1')} disableGutters square elevation={0}>
    <AccordionSummary
      expandIcon={<ExpandMoreIcon />}
      aria-controls="panel1bh-content"
      id="panel1bh-header"
    >
      <Typography sx={{ width: '33%', flexShrink: 0, fontFamily:'Montserrat', fontWeight:'600' }}>
        skin
      </Typography>
     
    </AccordionSummary>
    <AccordionDetails>
          <FilterDiv >
          <ArrowForwardIosOutlinedIcon fontSize='small' sx={{color:'#ccc', paddingRight:'20px'}}/>
          <StyledLink to='/filterProducts/skin/all'>all</StyledLink>
          </FilterDiv>
        </AccordionDetails>
  </Accordion>
  <Accordion expanded={expanded === 'panel2'} onChange={handleChange('panel2')} disableGutters square elevation={0}>
    <AccordionSummary
      expandIcon={<ExpandMoreIcon />}
      aria-controls="panel2bh-content"
      id="panel2bh-header"
    >
      <Typography sx={{ width: '33%', flexShrink: 0, fontFamily:'Montserrat', fontWeight:'600'  }}>body</Typography>
      
    </AccordionSummary>
    <AccordionDetails>
    <FilterDiv >
          <ArrowForwardIosOutlinedIcon fontSize='small' sx={{color:'#ccc', paddingRight:'20px'}}/>
          <StyledLink to='/filterProducts/body/all'>all</StyledLink>
          </FilterDiv>
    </AccordionDetails>
  </Accordion>
    </FilterContainer>
    <Products items={products}/>    
    </MainProductsContainer>
    <Footer/>
    </div>
  )
}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source