0

How to update an array of objects with clickHandler and useState in Reactjs?

import React, { useState } from 'react';

    const TextVote = () => {
      const [votes, setVotes] = useState([
        { text: 'OneOneOne', vote: 0 },
        { text: 'TwoTwoTwo', vote: 5 },
        { text: 'ThreeThreeThree', vote: 0 }
      ]);
      const votesHandler = () => {
        const newClicks = {
          ...votes,
          vote: votes[1].vote + 1
        };
        setVotes(newClicks);
      };

      return (
        <div className='box'>
          <div>{votes[1].text}</div>

          <div>
            <button onClick={votesHandler}>vote</button>
            <div>{votes[1].vote}</div>
          </div>
        </div>
      );
    };

    export default TextVote;

Want to know how to update the array and some feedback after the clicks of the updates. Right now it should update just one object, but it isn't. The basic idea is to vote for comments and return the comment with the most votes. It is a mock-up just to get ideas how it could work. I don't have the intention to render the whole array. Just the one with the most votes.

Haakon
  • 3
  • 1
  • 3
  • well currently you aren't updating an array of objects, you're just changing one element in the array. If you want to render multiple elements and or their related votes, you should map over them and render an element for each. Then you can use the click handler to pass the index or a unique mapper to your data to update – John Ruddell Jul 22 '19 at 17:36
  • 3
    Possible duplicate of [How do I update states onchange in an array of object in React Hooks](https://stackoverflow.com/questions/55987953/how-do-i-update-states-onchange-in-an-array-of-object-in-react-hooks) – John Ruddell Jul 22 '19 at 17:37

2 Answers2

2

The initial value of votes is array. But you are treating it as object.

const newClicks = {
          ...votes,
          vote: votes[1].vote + 1
        };

You should do something like this.

const newClicks = [...votes];
let newVote = { ...newClicks[1] };
newVote.vote++;
newClicks[1] = newVote;
setVotes(newClicks);

Enjoy!

Philip Moy
  • 481
  • 3
  • 6
1

What about this approach? The array of initial 0 votes for each item is stored in a state and then incremented with every "vote" click and stored in that array, which is being updated with every click. Also, every time it shows a random item. Of course you can change the length of the array (number of items).

const App = (props) => {
  const [selected, setSelected] = useState(0);
  const [points, setPoints] = useState(new Uint8Array(6));


const votesCount = () => {
  const newClicks = [...points];
  newClicks[selected] +=1;
  setPoints(newClicks);
}


const handleClick = () => {
  const randomNumber = Math.floor(Math.random()*props.itemsToVote.length);
  setSelected(randomNumber);
}

  return (
    <div>
      <p>{props.itemsToVote[selected]}</p>
      <p>Has {points[selected]} votes</p>
      <button onClick={handleClick}>Next</button>
      <button onClick={votesCount}>Vote</button>
    </div>
  )
}

const itemsToVote = ["item1", "item2", "item3", "item4", "item5", "item6", ]
Alicja
  • 11
  • 1