I’m trying to practice React by building a kind of ecommerce template and I’m currently experimenting with filtering products that contain the word/string clicked in a filter section.
I’ve created the below which pulls in all products from a json into a product array and then pulls in all the available categories and brands into a filter section:
I’m trying to make it so it updates the product feed to only show products that have a brand that matches the brand name/string clicked in the filters (example: clicking Essence would only show that one Essence brand product and not show the Glamour Beauty product)
I thought this would work but it just seems to remove all products so obviously I’ve got it wrong:
const [products, setProducts] = useState(props.productData.products)
const [productsLimit, setProductsLimit] = useState(props.productData.limit)
clickFilter = document.querySelectorAll('.filter .name');
clickFilter.forEach(cF => {
cF.addEventListener('click', (f) => {
f = f.target.textContent;
console.log(f);
setProducts(
products.filter(product => product.brand == f)
)
});
});
<div className='products'>
{/* checks the product data exists before mapping it */}
{products?.slice(0, productsLimit).map(product => (
<div className='product' key={product.id}>
<div className='productImage'>
<img src="" data-src={product.thumbnail} />
</div>
<div className='productInfo'>
<div className='productTitle'>
<div className='productBrand'>{product.brand}</div>
<div className='productName'>{product.title}</div>
</div>
<div className='productPrice'>Price: {product.price}</div>
</div>
</div>
))}
</div>
So help understanding what I’m doing wrong and how to get it working would be much appreciated thanks.
If you want you can simplify this by having a state hover the brands names and filter all your product on the render !
in quick code
const brands = ['brandA', 'brandB', 'brandC'];
function DisplayProducts(props: { products: { id: number; brand: string, name: string }[] }) {
const [filters, setFilters] = useState<string[]>([]);
const filteredProducts = props.products.filter(
(product) => filters.length === 0 ? product : filters.includes(product.brand),
);
return (
<>
{brands.map((brand) => (
<button
key={brand}
onClick={() =>
setFilters((prev) => {
if (prev.includes(brand)) return prev.filter((filter) => brand.localeCompare(filter));
return prev.concat(brand);
})
}
>
{brand}
</button>
))}
{filteredProducts.map((product) => (
<div key={product.id}>product.name</div>
))}
</>
);
}
To be more precise, when you click on a filter, it will add or remove it from the array of filters and so trigger a new render (or reconciliation in this case).
During the new render the variable filteredProducts
will be recalculated with the new set of filters.
If you are learning react right I highly recommend to read this part of the react doc react docs . Don’t worry it’s not a traditional doc, but some explanation on how to develop in react.
Now to understand with your code what is going wrong I will need a little bit more detail on how you implemented the filter on the left side.
jupremator is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.