0

I am trying to get value from the radio button the problem is I can get the values but when I tried to store on my state it only updates 2 times after the 3rd time when I try to update the state it is not updating.

Radio buttons code.

              <li>
                <label className="container_radio">
                  Small
                  <span>+ $5</span>
                  <input
                    type="radio"
                    required
                    onChange={(e) => handleChange(e, product)}
                    defaultValue={5}
                    name={"size"}
                  />
                  <span className="checkmark"></span>
                </label>
                <label className="container_radio">
                  Medium
                  <span>+ $10</span>
                  <input
                    type="radio"
                    required
                    onChange={(e) => handleChange(e, product)}
                    defaultValue={10}
                    name={"size"}
                  />
                  <span className="checkmark"></span>
                </label>
                <label className="container_radio">
                  Large
                  <span>+ $15</span>
                  <input
                    type="radio"
                    required
                    onChange={(e) => handleChange(e, product)}
                    defaultValue={15}
                    name={"size"}
                  />
                  <span className="checkmark"></span>
                </label>
              </li>

I am trying to achieve output something like this

[{title: 'Barnes Chapman', options:{Medium size: '5.00' } }]

My ui:

enter image description here

My function: problem is here if (isExist) { isExist.options = { ...isExist.options, [name]: value, }; return prevValue; for this code the state is not updaing unlimited time.

  const handleChange = (e, product) => {
    // Destructuring
    const { name, value, checked } = e.target;

    console.log(`${value} is ${checked} `);

    // Case 1 : The user checks the box
    if (checked) {
      setProductInfo((prevValue) => {
        const isExist = prevValue.find((item) => item.title === product.title);
        if (isExist) {
          isExist.options = {
            ...isExist.options,
            [name]: value,
          };
          return prevValue;
        } else {
          return [
            ...prevValue,
            {
              title: product.title,
              options: { [name]: value },
            },
          ];
        }
      });
    }

    // Case 2  : The user unchecks the box
    else {
      setProductInfo(productinfo.filter((e) => e.title !== name));
    }
  };
Jerin
  • 717
  • 1
  • 7
  • 28
  • please share more code. Especially which kind of array does `productinfo` hold? – Liki Crus Apr 13 '22 at 12:54
  • it's just a state which will store the radio button value and product title ` const [productinfo, setProductInfo] = useState([]); ` – Jerin Apr 13 '22 at 13:02
  • could you show me sample for an item in the array? – Liki Crus Apr 13 '22 at 13:03
  • Why are you returning the previous state if the ```isExist``` is true? – angel_dust Apr 13 '22 at 13:05
  • @Liki above function output `[options: {size: '15'} title: "Carroll Montgomery"]` if you want to play with my code here is the link of codesandbox https://codesandbox.io/embed/friendly-bird-ldqvb0?fontsize=14&hidenavigation=1&theme=dark – Jerin Apr 13 '22 at 13:12
  • @OsamuRenji I am retruning `previous state ` beacsue after 3rd time when I try to update the state it give me an error which is `Uncaught TypeError: Cannot read properties of undefined (reading 'find') ` – Jerin Apr 13 '22 at 13:13
  • @Jerin It means the item was not found. ```find``` method return ```undefined``` if the value was not found in the array. – angel_dust Apr 13 '22 at 13:15
  • @OsamuRenji I consoled `isExisit` but I didn't get any undefined, every time it gives me an object even after 3rd time when I try to update the state – Jerin Apr 13 '22 at 13:23
  • So the component isn't re-rendering even though you return ```prevValue```. Is that your problem? – angel_dust Apr 13 '22 at 13:25
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/243853/discussion-between-jerin-and-osamu-renji). – Jerin Apr 13 '22 at 13:29

1 Answers1

1

There are few problems in your code.

1. Don't change state variable directly.

In the following code, you are trying to change state variable directly. This may result unexpected result.

const isExist = prevValue.find((item) => item.title === product.title);
if (isExist) {
  isExist.options = {
    ...isExist.options,
    [name]: value,
  };
  return prevValue;
}

You can read more about it.

Why can't I directly modify a component's state

2. In this code, you should compare array item by title instead of name. Because you are using title.

    // Case 2  : The user unchecks the box
    else {
      setProductInfo(productinfo.filter((e) => e.title !== name));
    }

3. Updated code based on your code in codesandbox

import { useState } from "react";
import Select from "react-select";
import "./styles.css";

export default function App() {
  const [productinfo, setProductInfo] = useState([]);

  const handleChange = (e, product) => {
    // Destructuring
    const { name, value, checked } = e.target;

    console.log(`${value} is ${checked} ${product.title}`);

    // Case 1 : The user checks the box
    if (checked) {
      setProductInfo((prevValue) => {
        const newValue = prevValue ? [...prevValue] : [];
        const isExist = newValue.find((item) => item.title === product.title);
        if (isExist) {
          isExist.options = {
            ...isExist.options,
            [name]: value,
          };
          return newValue;
        } else {
          return [
            ...newValue,
            {
              title: product.title,
              options: { [name]: value },
            },
          ];
        }
      });
    }

    // Case 2  : The user unchecks the box
    else {
      setProductInfo(productinfo.filter((e) => e.title !== product.title));
    }
  };
  console.log(productinfo, "state");

  return (
    <div className="App">
      <ul className="clearfix">
        {/* {product.options.map((option, i) => {
                return ( */}
        <li>
          <label className="container_radio">
            Small
                  <span>+ $5</span>
            <input
              type="radio"
              required
              onChange={(e) => handleChange(e, { title: "title" })}
              defaultValue={5}
              name={"size"}
            />
            <span className="checkmark"></span>
          </label>
          <label className="container_radio">
            Medium
                  <span>+ $10</span>
            <input
              type="radio"
              required
              onChange={(e) => handleChange(e, { title: "title" })}
              defaultValue={10}
              name={"size"}
            />
            <span className="checkmark"></span>
          </label>
          <label className="container_radio">
            Large
                  <span>+ $15</span>
            <input
              type="radio"
              required
              onChange={(e) => handleChange(e, { title: "title" })}
              defaultValue={15}
              name={"size"}
            />
            <span className="checkmark"></span>
          </label>
        </li>
        {/* ); */}
        {/* // })} */}
      </ul>
    </div>
  );
}

Liki Crus
  • 1,901
  • 5
  • 16
  • 27