2

I have a code that has various colors and sizes that are repeated, but all I need is a single property. This code contains a radio button that provides you the overall quantity of the color red when you click it, but when you select a size, it gives you the precise quantity in the object of value. Is there a method or solve this problem?

Code


import React, { useState } from "react";

export default function ControlledRadios() {
  const data = [
    {
      id: 1,
      name: "Product A",
      attributes: [
        {
          id: 1,
          color: "Red",
          size: "Small",
          qty: 200,
        },
        {
          id: 2,
          color: "Red",
          size: "Medium",
          qty: 100,
        },
        {
          id: 3,
          color: "Red",
          size: "Large",
          qty: 300,
        },
        {
          id: 4,
          color: "Yellow",
          size: "Small",
          qty: 200,
        },
        {
          id: 5,
          color: "Yellow",
          size: "Medium",
          qty: 100,
        },
        {
          id: 6,
          color: "Yellow",
          size: "Large",
          qty: 300,
        },
      ],
    },
  ];

  const totalQty = data.map(({ attributes }) => {
    return attributes.reduce((total, { qty }) => {
      return (total += qty);
    }, 0);
  });
  console.log(totalQty);

  const [qty, setQty] = useState(totalQty);

  const handleChange = (event) => {
    const id = event.target.value;
    const targetAttribute = data[0].attributes.find((x) => x.id == id);
    if (event.target.name === "schedule-weekly-option-color") {
      let sum = 0;
      data[0].attributes.forEach((a) => {
        if (a.color === targetAttribute.color) {
          sum += a.qty;
        }
      });
      setQty(sum);
    } else {
      let sum = 0;
      data[0].attributes.forEach((a) => {
        if (
          a.color === targetAttribute.color &&
          a.size === targetAttribute.size
        ) {
          sum += a.qty;
        }
      });
      setQty(sum);
    }
  };

  return (
    <>
      <h1>Quantity: {qty}</h1>
      <fieldset value={qty} onChange={(event) => handleChange(event)}>
        <h3>Color:</h3>
        {data.map(({ attributes }) => {
          return attributes.map((a) => (
            <>
              <label key={a.id}>
                <input
                  type="radio"
                  name="schedule-weekly-option-color"
                  value={a.id}
                />
                {a.color}
              </label>
              <br />
            </>
          ));
        })}
        <h3>Size:</h3>
        {data.map((item) => {
          return item.attributes.map((a) => (
            <>
              <label key={a.id}>
                <input
                  type="radio"
                  name="schedule-weekly-option-size"
                  value={a.id}
                />
                {a.size}
              </label>
              <br />
            </>
          ));
        })}
      </fieldset>
    </>
  );
}

This is the code I have right now, and it demonstrates what I mean when I say "repeated color and size."

enter image description here

As seen above the image, I have this duplicate colors but if I press only the color red it will give me the total quantity of 600 but if I press a **size small with the color red** it will give me the total quantity of 200

Is there a method to get rid of duplicate colors or sizes without breaking the functionality of my code?

1 Answer 1

1

I think you are storing the incorrect state. Selected/filtered quantity is derived state from the data and the selected filter. Store the filters in state and compute the derived state.

Create the selected filter state and handler.

const [color, setColor] = useState("");
const [size, setSize] = useState("");

const handleChange = (event) => {
  const { value, name } = event.target;

  if (name === "schedule-weekly-option-color") {
    setColor(value);
  } else {
    setSize(value);
  }
};

Create your de-duped options. Map the attribute into a Set and convert back to an array.

const colorOptions = Array.from(
  new Set(data[0].attributes.map((el) => el.color))
);

const sizeOptions = Array.from(
  new Set(data[0].attributes.map((el) => el.size))
);

Compute the derived filtered total quantity. Filter by the selected radio option values, then reduce the filtered result into a total quantity.

const qty = data[0].attributes
  .filter((el) => {
    if (color || size) {
      if (color && size) {
        return el.color === color && el.size === size;
      }
      return el.color === color || el.size === size;
    }
    return true;
  })
  .reduce((qty, current) => qty + current.qty, 0);

Render the results. The React key should be on the outermost mapped element.

return (
  <>
    <h1>Quantity: {qty}</h1>
    <fieldset value={qty} onChange={handleChange}>
      <h3>Color:</h3>
      {colorOptions.map((color) => (
        <Fragment key={color}>
          <label>
            <input
              type="radio"
              name="schedule-weekly-option-color"
              value={color}
            />
            {color}
          </label>
          <br />
        </Fragment>
      ))}
      <h3>Size:</h3>
      {sizeOptions.map((size) => (
        <Fragment key={size}>
          <label>
            <input
              type="radio"
              name="schedule-weekly-option-size"
              value={size}
            />
            {size}
          </label>
          <br />
        </Fragment>
      ))}
    </fieldset>
  </>
);

Edit how-to-remove-duplicate-object-value-in-an-array-in-reactjs

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

Hello, thanks for answering this is what I needed, thanks so much

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.