How to set the state when it is an array of objects

Viewed 106

So i want to build a voting app thing, and I need to set the number of votes into state so that it updates on click.But I don't exactly know how to set one property of an object without disrupting the other oroperty and the other object.

import './App.css';
import React, {useState} from 'react'

function App() {
    const [votes, setVotes] = useState([
        {
            voteNum: 0,
            name: "Item 1"
        },
        {
            voteNum: 0,
            name: "Item 2"
        }
    ])
    
    
    const addVote = (vote) => {
        vote.voteNum++
        setVotes( /* How do I set the votes.voteNum to be equal to vote.voteNum from the line above */)
    }

  return (
    <div className="App">
        <h1>Cast Your Votes!</h1>

        {votes.map(vote => (
            <form className="votee" onClick={() => addVote(vote)}>
                <h1>{vote.voteNum}</h1>
                <h2>{vote.name}</h2>
            </form>
        ))}
    </div>
  );
}

export default App;
3 Answers

You should update react state in immutable way:

const addVote = (vote) => {
     setVotes(votes.map(x => x === vote ? ({
        ...x,
        voteNum: x.voteNum + 1
    }) : x))
}

Or better use some unique Id in comparison, e.g. x.id === vote.id if you have Ids for your objects; or as mentioned in another answer, you can also use element array index in comparison (pass that to the function instead of vote).

const addVote = (vote) => {
    const _votes = JSON.parse(JSON.stringify(votes))
    const index = _votes.findIndex(v => v.name === vote.name)
    if (index !== -1) {
        _votes[index].voteNum ++
    }
    setVotes(_votes)
}

Pass index to function

{votes.map((vote, index) => (
        <form className="votee" onClick={() => addVote(index)}>
            <h1>{vote.voteNum}</h1>
            <h2>{vote.name}</h2>
        </form>
    ))}

addVote function would look like

const addVote = (index) => {
    votes[index].voteNum ++;
    setVotes([...votes]);
}

Note: Usestate is prefrered to use primitive data types i.e string, boolean and number For array and object make use of useReducer

Related