Home > Software engineering >  I can't properly change the boolean of an array with prevState
I can't properly change the boolean of an array with prevState

Time:09-30

I'm trying to display the comments of each photo when clicked the button. Got stuck with setObj function. When I click I can change the boolean but also it pushes another item named "true" to the array.

export default function App() {
  const [obj, setObj] = useState([
    { name: "chicken", comments: "nice", photo: img, boolean: false },
    { name: "beef", comments: "ehh", photo: img, boolean: false },
    { name: "turkey", comments: "not bad", photo: img,  boolean: false },
    { name: "broccoli", comments: "cool", photo: img,  boolean: false },
    {
      name: "carrot",
      comments: "disgusting",
      photo: img,
      key: 4,
      boolean: false
    }
  ]);
  const handleClick = (e) => {
    const idx = e.target.value;
    setObj(prev => 
      [...prev, prev[idx].boolean = true]
    )
    console.log(obj);
  };




 return (
    <div>
      {obj.map((map, key) => (
        <div>
          <img src={map.photo} alt={map.key} />
          <h1>{map.name}</h1>
          <p>{`${map.boolean}`}</p>
          <p>{key}</p>

Haven't done the neccessary changes here coz i got stuck with setState function.

          <button value={key} onClick={handleClick}>
            show comments
          </button>
        </div>
      ))}
    </div>
  );
}
//onClick={(e) => {
//map.boolean = !e.target.value
//setObj([...obj])
//}}value={map.boolean}

CodePudding user response:

Well, this is actually what you are doing there, you are spreading an array and adding an item after that! what you could do:

const handleClick = (e) => {
    const idx = e.target.value;
    setObj(prev => {
       prev[idx].boolean = true;
       return prev;
      } 
    )
    console.log(obj);
  };

this would work most likely.

also for this kind of huge states I suggest you consider useReducer from react.

CodePudding user response:

The issue is here

setObj(prev => 
      [...prev, prev[idx].boolean = true]
)

You're actually pushing another boolean value modify handleClick function as such

const handleClick = (e) => {
    const idx = e.target.value;// getting the required idx
    const newObj = JSON.parse(JSON.stringify(obj)); // creating a new obj 
    obj[idx].boolean = true; // setting the newobj boolean value
    setObj(newObj); // useState function to set new state.
};

CodePudding user response:

This is what's called a destructuring assignment

[...prev, prev[idx].boolean = true]

You basically say.. Hey, take this object, spread it's values, then assign this new value and append it. The problem with this is that you're creating a new variable prev[idx].boolean and assigning a new value to it true. That's the root of the problem.

Now, what you should do is create this variable outside

const value = { ...prev[idx] }
value.boolean = true

You should create a new object otherwise it's passed by reference.

In Pass by Reference, a function is called by directly passing the reference/address of the variable as the argument. Changing the argument inside the function affects the variable passed from outside the function. In Javascript objects and arrays are passed by reference.

Then assign it

setObj(prev => 
  [...prev, value]
)

This means you will override any destructured element with the same value or if it doesn't have any, just assign the new value.

  • Related