How to create a product page with variant dropdowns in react?

2.2k Views Asked by At

What's the best way to create a product page with variant dropdowns? I have a product with list of variants eg:

[{size: "small", color: "red", material: "metal"},
{size: "small", color: "red", material: "wood"},
{size: "medium", color: "blue", material: "plastic"},
{size: "large", color: "blue", material: "metal"},
{size: "large", color: "yellow", material: "wood"}]

What i did was create 3 dropdowns one for size, one for color and one for material that has all available options listed.

I need a way to affect the other 2 dropdowns when one of the dropdowns is changed so that only the available variations are available in the dropdowns.

For example if the user selects "small" from the first dropdown, the color dropdown should only show red and the material dropdown should only show metal and wood.

What's the best way to achieve this?

I have created the example of 3 dropdowns in this codesandbox: https://codesandbox.io/s/divine-water-vz8tv?file=/src/App.js

1

There are 1 best solutions below

0
On BEST ANSWER

You can collect options every time the value of one of the select changes. It remains only to finalize the reset of dependent selects when re-selecting the main (on setSize reset color and material, on setColor reset material).

Codesandbox

const products = [
  { size: "small", color: "red", material: "metal" },
  { size: "small", color: "red", material: "wood" },
  { size: "medium", color: "blue", material: "plastic" },
  { size: "large", color: "blue", material: "metal" },
  { size: "large", color: "yellow", material: "wood" }
];

export default function App() {
  const [size, setSize] = React.useState();
  const [color, setColor] = React.useState();
  const [material, setMaterial] = React.useState();

  const sizeOptions = products
    .map((p) => p.size)
    .filter((v, i, a) => a.indexOf(v) === i)
    .map((size) => ({ label: size, value: size }));
  const colorOptions = products
    .filter((p) => size && p.size === size.value)
    .map((p) => p.color)
    .filter((v, i, a) => a.indexOf(v) === i)
    .map((color) => ({ label: color, value: color }));
  const materialOptions = products
    .filter(
      (p) => size && p.size === size.value && color && p.color === color.value
    )
    .map((p) => p.material)
    .filter((v, i, a) => a.indexOf(v) === i)
    .map((material) => ({ label: material, value: material }));

  return (
    <div className="App">
      <Select value={size} onChange={setSize} options={sizeOptions} />
      <Select
        value={color}
        onChange={setColor}
        options={colorOptions}
        isDisabled={!size}
      />
      <Select
        value={material}
        onChange={setMaterial}
        options={materialOptions}
        isDisabled={!color}
      />
    </div>
  );
}