Home > Net >  How to increment selected value in array with button
How to increment selected value in array with button

Time:11-08

I've tried so many different solutions, but cannot find the one that would work. I have an array of anecdotes and an array of votes that coincide with each anecdote. I can display the selected matching anecdote and vote, but have been unable to increase by 1 the selected/displayed vote for its respective anecdote. How would I code the button to increase the selected/displayed vote by 1 and update the array to display that change?

import { useState } from 'react'


const App = () => {
  const anecdotes = [
    'If it hurts, do it more often.', 
    'Adding manpower to a late software project makes it later!',
    'The first 90 percent of the code accounts for the first 10 percent of the development time...The remaining 10 percent of the code accounts for the other 90 percent of the development time.',
    'Any fool can write code that a computer can understand. Good programmers write code that humans can understand.',
    'Premature optimization is the root of all evil.',
    'Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.',
    'Programming without an extremely heavy use of console.log is same as if a doctor would refuse to use x-rays or blood tests when diagnosing patients.', 
  ]

  const [selected, setSelected] = useState(0)
  const points = { 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6 }
  const copy = {...points}
  const [votes, setVotes] = useState(copy)
  const voteClick = () => setVotes(votes[selected] =1)
 

 const randAnecdote = e => {
    const len = anecdotes.length;
    setSelected(Math.floor(Math.random() * len));
  };
 
  return (
    <div>
      <div>{anecdotes[selected]}</div><br />
      This anecdote {copy[selected]} votes<br />
      <button onClick={voteClick}>Vote</button><button onClick={randAnecdote}> Next Anecdote</button>
    </div>
  )
}

export default App


I have tried useState, I have tried a more basic form of incrementing, I have tried many different solutions. I want the selected/displayed vote value in the copy array to increase by 1 and when switching to a new, random anecdote and vote, I want the button to increase that selected/displayed vote value by 1. Nothing has worked.

CodePudding user response:

you can simplify the data and use the same object for both of anecdotes and votes.

I updated your code to the following:

import { useState, useEffect } from "react";
import "./styles.css";

/** NANOID */
import { nanoid } from "nanoid";

export default function App() {
  const [anecdotes, setAnecdotes] = useState([]);
  const [selected, setSelected] = useState(null);

  useEffect(() => {
    /** HERE YOU SHOULD DO AN API CALL.
     *  THE RETURN SHOULD BE EQUAL TO FORMATTED VARIABLE
     */
    const data = [
      "If it hurts, do it more often.",
      "Adding manpower to a late software project makes it later!",
      "The first 90 percent of the code accounts for the first 10 percent of the development time...The remaining 10 percent of the code accounts for the other 90 percent of the development time.",
      "Any fool can write code that a computer can understand. Good programmers write code that humans can understand.",
      "Premature optimization is the root of all evil.",
      "Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.",
      "Programming without an extremely heavy use of console.log is same as if a doctor would refuse to use x-rays or blood tests when diagnosing patients."
    ];
    const points = [0, 1, 2, 3, 4, 5, 6];
    const formatted = data.map((anecdote, index) => ({
      id: nanoid(),
      sentence: anecdote,
      points: points[index] ?? 0
    }));

    setAnecdotes(formatted);

    formatted.length > 0 && setSelected(formatted[0]);
  }, []);

  const handleVote = () => {
    if (selected === null) return;

    /** CREATE A NEW COPY */
    const tmp = JSON.parse(JSON.stringify(anecdotes));
    const index = anecdotes.findIndex(
      (anecdote) => anecdote.id === selected.id
    );

    if (index === -1) return;

    tmp[index].points  = 1;

    setSelected((current) => ({ ...selected, points: current.points   1 }));
    setAnecdotes(tmp);
  };

  const handleNext = () => {
    const index = anecdotes.findIndex(
      (anecdote) => anecdote.id === selected.id
    );

    if (index === anecdotes.length - 1) {
      setSelected(anecdotes.at(0));
    } else {
      setSelected(anecdotes.at(index   1));
    }

  };

  if (selected === null) {
    return <p>Loading</p>;
  }

  return (
    <div>
      <div>{selected.sentence}</div>
      <br />
      This anecdote has {selected.points} votes
      <br />
      <button onClick={handleVote}>Vote</button>
      <button onClick={handleNext}> Next Anecdote</button>
    </div>
  );
}

You should use a service to fetch the data (inside the useEffect). It's a js version but I recommend you to use Typescript.

Here is the link to the sandbox: https://codesandbox.io/s/white-snowflake-x6c6m1?file=/src/App.js .

CodePudding user response:

You need to pass a new dictionary with points to the setVotes function. Right now what you are doing is mutating the existing dictionary and pass a number to the setVotes function.

Your voteClick function should look more like this:

const voteClick = (selected) => {
  const newVotesDict = {...votes};
  newVotesDict[selected]  = 1;
  setVotes(newVotesDict);
}

First it is important that you create a new object using the spread operator, then you pass that object to the setVotes function.

  • Related