Can't make the background changing if selected (really hard to resolve) React and Hydrogen

98 Views Asked by At

I would like to know how can I make any button changing color when selected.

Knowing that you can only selected one button at the time for each value.

Like if you click on 'White', the Black button can't have the same background color. Same for the Size, if 'L' is selected, and you click on 'S' then, 'L' take the default color and 'S' the background color when an element is selected.

What it look like now

Thanks in advance to anyone who tries to help me!

I've tried to use If Statement but I'm not sure I'm doing it right.

           {values.map((value) => {
              
              const id = `option-${name}-${value}`;
              const checked = setSelectedOption[name] === value;

              const [bgSelected, setBgSelected] = useState(false);

              const handleClick = () => {
                  setBgSelected(!bgSelected);
              }

              const handleSelected = () => {
                setSelectedOption(name, value);
                if (bgSelected === true) {
                  setBgSelected(false);
                  handleClick()
                } else {
                  setBgSelected(true);
                  handleClick()
                 }
                
              }



              return (
                <div key={id} className="product-option-value text-left">
                  <div 
                    type="button" 
                    checked={checked}
                    name={name}
                    value={value}
                    id={id}
                   // onChange={() =>setSelectedOption(name, value)}
                    className=""
                  />
                  <label 
                    htmlFor={id}
                    //onClick={handleClick}
                    className={bgSelected ? "bg-blue-800" : "bg-blue-200"}
                    onClick={handleSelected}

                  >{value}</label>


                </div>
              )
            })}

          </div>
1

There are 1 best solutions below

6
On BEST ANSWER

It seems like you are calling the wrong property from useProductOptions to determine if your product has been selected, you are using setSelectedOption[name] instead of the selectedOptions[name].

Based on this one value (selectedOptions[name]) you can also determine if a value has been selected so you do not need to create an extra state for the background.

Try and use:

function ProductForm({ product }) {
  const { options, selectedVariant, selectedOptions, setSelectedOption } =
    useProductOptions();

  const isOutOfStock = !selectedVariant?.availableForSale || false;

  return (
    <div className="drop-shadow-xl bg-white rounded-xl p-10 w-7/12">
      <h1 className="font-bold text-3xl">{product.title}</h1>
      <ProductPrice
        className="font-light text-lg pb-3"
        data={product}
        variantId={selectedVariant.id}
      />

      <div className="product-option">
        {options.map(({ name, values }) => {
          if (values.length === 1) {
            return null;
          }
          return (
            <div
              key={name}
              className="product-option-group sm:grid-cols-2 flex items-center gap-3"
            >
              <legend className="product-option-name font-bold text-lg py-3 w-12">
                {name}
              </legend>

              {values.map((value) => {
                const id = `option-${name}-${value}`;
                const checked = selectedOptions[name] === value;

                return (
                  <div key={id} className="product-option-value text-left">
                    <div
                      type="button"
                      checked={checked}
                      name={name}
                      value={value}
                      id={id}
                      className=""
                    />
                    <label
                      htmlFor={id}
                      className={checked ? "bg-blue-800" : "bg-blue-200"}
                      onClick={() => setSelectedOption(name, value)}
                    >
                      {value}
                    </label>
                  </div>
                );
              })}
            </div>
          );
        })}
      </div>

      <AddToCartButton
        disabled={isOutOfStock}
        className="add-to-cart font-bold text-md p-2 rounded-3xl mt-3 bg-slate-300 hover:bg-slate-400"
      >
        {isOutOfStock ? "Out of stock" : "Add to cart"}
      </AddToCartButton>
    </div>
  );
}

=== old answer before the post update ===

I am not sure why your code is not throwing errors, but you should (and can) not use a useState inside of a map.

You could write this component using just one state, as below.

A working example can be found at this codesandbox

const values = [
  {
    id: 1,
    name: "test",
    value: "option 1"
  },
  {
    id: 2,
    name: "test",
    value: "option 2"
  },
  {
    id: 3,
    name: "test",
    value: "option 3"
  }
];
const MyComponent = () => {
  const [selectedValue, setSelectedValue] = useState(values[0]);

  return (
    <>
      {values.map(({ id, value, name }) => {
        const isSelected = selectedValue === id;
        return (
          <div key={id} className="product-option-value text-left">
            <input
              type="radio"
              checked={isSelected}
              name={name}
              value={value}
              id={id}
              onChange={() => setSelectedValue(id)}
            />
            <label
              htmlFor={id}
              style={{ background: isSelected ? "red" : "blue" }}
            >
              {value}
            </label>
          </div>
        );
      })}
    </>
  );
};