Skip to content
Advertisement

React – how to display all products using dropdown?

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.

Advertisement