First time trying to do this so please bear with me.
I’m using a dropdown to filter product data from a local JSON file based on category. The code below does filter and display the products based on category when a user selects a category. However I’d like to show all of the products on load before the user selects a category. Currently it just shows a blank page, until a user clicks a category and then it filters and shows products.
Here’s the filter code:
// Load in global state const { data, isLoading } = useAPI(); const [selectedCategory, setSelectedCategory] = useState("All"); const filteredCategories = data.filter( (machine) => machine.category.toLowerCase() === selectedCategory.toLowerCase() );
The JSON is here.
Dropdown code:
<div className="options"> {!isLoading ? ( <> <select value={selectedCategory} onChange={(e) => setSelectedCategory(e.target.value)} className="product-dropdown" name="product-dropdown" > <option value="">All</option> {data.map((item) => ( <option value={item.category}>{item.category}</option> ))} </select> </> ) : ( <p>Loading...</p> )} </div>
Lastly the code to render out the products:
export default function MachineList({ filteredCategories, filteredSearch }) { return ( <> {filteredCategories.map((item) => ( <ul> {/* Filter and map through the second level of API */} <div className="row"> {item.product_details.filter(filteredSearch).map((subItem) => ( <MachineCard image={subItem.image} title={subItem.model} weight={subItem.operating_weight} power={subItem.power} /> ))} </div> </ul> ))} </> ); }
Any idea how I can show all of the products on load?
Advertisement
Answer
The problem is that you filter based on whether the category of a product from db.json
is equal to the selectedCategory
state toLowerCase
.
The reason this is a problem here is because it doesn’t account for the fact that 'All'
isn’t a category in your data. The filter
call will always filter out all your data when selectedCategory
is equal to 'All'
.
You want 'All'
to mean: Don’t filter the data.
You can achieve this by changing your filter logic to something like this:
let filteredCategories = data; if (selectedCategory !== "All") { filteredCategories = data.filter( (machine) => machine.category.toLowerCase() === selectedCategory.toLowerCase() ); }
Also in your select:
<select value={selectedCategory} onChange={(e) => setSelectedCategory(e.target.value)} className="product-dropdown" name="product-dropdown" > <option value="">All</option> {data.map((item) => ( <option value={item.category}>{item.category}</option> ))} </select>
change:
<option value="">All</option>
to:
<option value="All">All</option>
Since you pass e.target.value
to setSelectedCategory
, if you select an option other than 'All'
and select the 'All'
option after, it will cause your selectedCategory
state to be set to an empty string. The if
statement in the above filter logic doesn’t account for this. So change the option value
prop to 'All'
or add an extra condition to the if
statement. I recommend the former.