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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.