0

I am trying to update an array of object which contain my checkbox data. I need to update the value field when user clicks the checkbox. I think I can achieve this by using a mapping through the array and then using the spread operator to update the state.

My doubt is why the state is updating when using a find method? I thought only set method can update the state. Sorry in advance if this is an obvious noobie mistake.

let checkBoxDataTemp = [
  {
    name: "spam",
    value: false,
  },
  {
    name: "dangerousProduct",
    value: false,
  },
  {
    name: "sexuallyExplicit",
    value: false,
  },
  {
    name: "other",
    value: false,
  },
];

const [checkBoxData, setCheckBoxData] = useState(checkBoxDataTemp);

const changeInput = (input) => {
  const { name, value } = input;
  // Why is the below code updating the state eventhough I am not using setCheckBoxData
  checkBoxData.find((item) => item.name === name).value = value;
};

please check the changeInput function.

EDIT: How to approach incase of data that should remain unchanged?


let checkBoxDataTemp = [
  {
    name: "spam",
    label: "Spam", 
    value: false,
  },
  {
    name: "dangerousProduct",
    label: "Dangerous products",
    value: false,
  },
  {
    name: "sexuallyExplicit",
    label: "Sexually explicit"
    value: false,
  },
  {
    name: "other",
    label: "Other",
    value: false,
  },
];

  • 1
    Because you are mutating the array. Rule #1 in react - don't mutate state. Just because you are "allowed" to mutate, doesn't mean you should. – Adam Jenkins Jul 13 '21 at 15:34
  • This "update" depends entirely on how you observe it. Since you're not setting the state, as soon as the component re-renders your change will be lost. But within the current render, any modifications you make to that state variable will be visible just like any other variable in JavaScript. – David Jul 13 '21 at 15:40

1 Answers1

1

My doubt is why the state is updating when using a find method?

The find method isn't mutating the array, the assignment operator is:

checkBoxData.find((item) => item.name === name).value = value;

// is the same as
const someItem = checkBoxData.find((item) => item.name === name);
someItem.value = value // <-- this line

React state isn't special in this way, it's just a variable that you can mutate. But you absolutely never ever should update it without using the set method returned from useState.

EDIT: changeInput should look like this:

const changeInput = ({name,value}) => {
  setCheckboxData(data => data.map(item => item.name === name ? {...item,value} : item));
};
Adam Jenkins
  • 51,445
  • 11
  • 72
  • 100
  • Is this approch a bad practice in react? Instead of mutating should I go with map followed by spread and using set method approach? Please tell me why this is a bad approach if it is so? – milindsoorya Jul 13 '21 at 15:40
  • @milindsoorya: It's bad because it gives that render a false view of the current state, which could change at any time with a re-render. If you need to update the state, use the setter from `useState` to update it. As for the "right way" to do what you're currently doing... What exactly are you achieving currently? What's the goal? Right now all the example shows is mutating a state value for no reason, so the only answer is "don't do that". – David Jul 13 '21 at 15:51
  • 1
    @milindsoorya, see my edit. Yes. This approach is not only a bad practice, but it results in bugs. Never mutate things in react (which is why I particularly hate mobx, at least in react - it works, but it encourages "magic" behaviour). state/props in react should be treated as immutable. It helps if you treat everything as immutable in react. – Adam Jenkins Jul 13 '21 at 16:23
  • @adam, saw the edit. I really like the one-liner solution. But may I ask how you would approach it if there were some other key-value pairs other than name and value, and they should remain unchanged. I have added an example array as EDIT in the original question. – milindsoorya Jul 13 '21 at 17:03
  • 1
    @milindsoorya I've edited again to suit your needs, so `value` is now the only element that gets changed. – Adam Jenkins Jul 13 '21 at 17:11