1

I am trying to use hooks to add numbers from an array together. Currently it's a voting system. The result of adding all the numbers using a map statement gives me 0. I am pretty sure this has to do with useState not updating in time to add the numbers, therefore it's always giving me zero. I know I could put them in a separate array, and add that, but that seems a little verbose for something that would seem so simple.

Here is the code I have that produces 0

const PollResultsContainer = (props) => {
    const option = props.option
    const [totalVotes, setTotalVotes] = useState(0)

    useEffect(() => {
        let newVote
        if (option.length > 0) {
            option.map(opt => {
                newVote = opt.optionVotes + totalVotes
            })
        }
        setTotalVotes(newVote)
    }, [totalVotes])
    console.log(totalVotes)
    return (
        <>
            <div className='poll-results-div'>
                <TitleCardNS title={`${totalVotes}`} size='2.5rem' align='center' color='white' />
            </div>
lakerskill
  • 1,019
  • 1
  • 11
  • 24
  • This seems like an abuse of `useEffect` and should cause an extra render for no reason. What are you trying to achieve here? – ggorlen Nov 22 '19 at 01:42
  • adding all the votes together and then getting a percentage based on those votes per individual item. – lakerskill Nov 22 '19 at 02:31
  • If you have a better method I'll accept your answer to keep future users on the right path performance wise – lakerskill Nov 22 '19 at 02:32
  • Why do you need `useEffect` for that? Can you not total them up synchronously? `useEffect` is generally for things like HTTP requests and DOM refs. I can provide an answer but please provide a [mcve] and show `option` so I can run your code. See [this](https://stackoverflow.com/a/57003236/6243352) – ggorlen Nov 22 '19 at 02:32
  • I thought useState inside an if statement was a no no, and I would need to put in inside useEffect if I am going to do that – lakerskill Nov 22 '19 at 02:34
  • Yeah, I wouldn't put `useState` in an `if`. All of these seem like anti-patterns, but it's still difficult to tell what you're trying to accomplish. Seems like an [x-y problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Likely, there is a very simple solution if the problem you're trying to solve is made clear. – ggorlen Nov 22 '19 at 02:38
  • I had no idea x-y problem existed but now that I know I do this a lot. This was extremely insightful. – lakerskill Nov 23 '19 at 18:42

3 Answers3

3

There is not need to store it in a state.

const PollResultsContainer = ({option}) => {
  let totalVotes = option.reduce((acc, {optionVotes}) => acc + optionVotes, 0);
  console.log(totalVotes);
};
0

I added another variable into the equation. This probably solved the problem of useState not updating in time.

const PollResultsContainer = (props) => {
    const option = props.option
    const [totalVotes, setTotalVotes] = useState(0)
    let newVote = 0

    useEffect(() => {
        if (option.length > 0) {
            option.map(opt => {
                newVote = opt.optionVotes + newVote
                console.log(newVote)
            })
        }
        console.log(newVote)
        setTotalVotes(newVote)
    }, [totalVotes])
    console.log(totalVotes)
lakerskill
  • 1,019
  • 1
  • 11
  • 24
0

I don't think you need any state or effect in this component :

const PollResultsContainer = (props) => {
    const option = props.option
    let totalVotes = 0;

    if (option.length > 0) {
        option.forEach(opt => {
            totalVotes += opt.optionVotes
        })
    }
    console.log(totalVotes)
Mohamed Ramrami
  • 12,026
  • 4
  • 33
  • 49
  • Damn these are both good answers with the forEach and reduce usage. I chose yours cause it was first answered. Appreciate – lakerskill Nov 23 '19 at 00:08
  • Choosing answers by "who's first" doesn't help future visitors who had the same problem as you. Choose the best answer. In this answer, `if (option.length > 0)` is basically noise because `option.forEach` will simply not fire the callback if `option` is empty. – ggorlen Nov 23 '19 at 18:44