Nasem
Nasem

Reputation: 547

How to save the inputs in an array in nextjs?

I'm trying to save the inputs from the user when they click on the options of the questions. I have a function saveSelectedAnswers(questionIndex, answer) and in this function I want to save all the answers in an array so when later purposes like saving the answers in the db or justifying how many were correct or wrong.

I tried to do that on my own and the results are not worth showing.

How can I do it?

export default function ExamOne() {
  const questions = [
    { q: "What is the name of your country?", opt1: "Japan", opt2: "Russia" },
    { q: "What do you do?", opt1: "Student", opt2: "Doctor" },
    { q: "How old are you?", opt1: "12", opt2: "18" },
    { q: "What is your cat's name?", opt1: "Alex", opt2: "John" },
    { q: "Which platform do you like?", opt1: "YouTube", opt2: "Facebook" },
  ];

  const [currentQuestionNumber, setCurrentQuestionNumber] = useState(0);
  const [selectedAnswers, setSelectedAnswers] = useState([]);

  const changeToNextQuestion = () => {
    if (currentQuestionNumber !== questions.length - 1) {
      setCurrentQuestionNumber(currentQuestionNumber + 1);
    }
  };

  const changeToPreviousQuestion = () => {
    if (currentQuestionNumber !== 0) {
      setCurrentQuestionNumber(currentQuestionNumber - 1);
    }
  };

  const newArr = new Array(4);
  const saveSelectedAnswers = (index, answer) => {
    newArr[index] = answer
    console.log(newArr);
    setSelectedAnswers(newArr);
  };

  return (
    <div>
      <div>
        <p>{questions[currentQuestionNumber].q}</p>
        <p onClick={() => saveSelectedAnswers(currentQuestionNumber,questions[currentQuestionNumber].opt1)}>
          {questions[currentQuestionNumber].opt1}
        </p>
        <p onClick={() => saveSelectedAnswers(currentQuestionNumber,questions[currentQuestionNumber].opt2)}>
          {questions[currentQuestionNumber].opt1}
        </p>
      </div>

      <div>
        <button onClick={() => changeToPreviousQuestion()}>Previous</button>
        <button onClick={() => changeToNextQuestion()}>Next</button>
      </div>
    </div>
  );
}

Edit: When I click on any answers, here's the result: selectedAnswers:['Japan', empty × 3] selectedAnswers: (4) [empty × 2, '12', empty] selectedAnswers: (4) [empty, 'Student', empty × 2]

Upvotes: 1

Views: 1345

Answers (1)

jsN00b
jsN00b

Reputation: 3691

Presented below is one possible way to achieve the desired objective.

NOTE Please use FULL PAGE (a small clickable link on the right-bottom of the snippet, after "Run Code Snippet" and "Expand Snippet") to view the result.

Code Snippet

const {useState, useEffect} = React;

function ExamOne() {
  const questions = [
    { q: "What is the name of your country?", opt1: "Japan", opt2: "Russia" },
    { q: "What do you do?", opt1: "Student", opt2: "Doctor" },
    { q: "How old are you?", opt1: "12", opt2: "18" },
    { q: "What is your cat's name?", opt1: "Alex", opt2: "John" },
    { q: "Which platform do you like?", opt1: "YouTube", opt2: "Facebook" },
  ];

  const [currentQuestionNumber, setCurrentQuestionNumber] = useState(0);
  // set array initially as empty-string with
  // number of questions as array length
  const [selectedAnswers, setSelectedAnswers] = useState(
    [...Array(questions.length).keys()].map(x => '')
  );
  
  // use-effect is better suited to display console
  // when curr-qn-number changes
  useEffect(() => {
    console.log(
      `question: ${
        currentQuestionNumber
      } | choice: ${
        selectedAnswers[currentQuestionNumber] || 'none'
      }\n array: ${
        JSON.stringify(selectedAnswers)
      }`
    );
  }, [selectedAnswers]);
  // using "`" backtick / template-string to display
  // info on console (other methods may be used instead)
  
  const changeToNextQuestion = () => {
    if (currentQuestionNumber !== questions.length - 1) {
      setCurrentQuestionNumber(currentQuestionNumber + 1);
    }
  };

  const changeToPreviousQuestion = () => {
    if (currentQuestionNumber !== 0) {
      setCurrentQuestionNumber(currentQuestionNumber - 1);
    }
  };

  // use "set" with call-back function to update the current-state
  // using the "prev" (previous) state values.
  const saveSelectedAnswers = (index, answer) => {
    setSelectedAnswers(prev => {
      const curr = [...prev];
      curr[index] = answer;
      return curr;
    });
  };

  return (
    <div>
      <div>
        <p>{questions[currentQuestionNumber].q}</p>
        <p onClick={() => saveSelectedAnswers(currentQuestionNumber,questions[currentQuestionNumber].opt1)}>
          {questions[currentQuestionNumber].opt1}
        </p>
        <p onClick={() => saveSelectedAnswers(currentQuestionNumber,questions[currentQuestionNumber].opt2)}>
          {questions[currentQuestionNumber].opt2}
        </p>
      </div>

      <div>
        <button onClick={() => changeToPreviousQuestion()}>Previous</button>
        <button onClick={() => changeToNextQuestion()}>Next</button>
      </div>
    </div>
  );
}


ReactDOM.render(
  <div>
    <div className="demoTitle">DEMO</div>
    <ExamOne />
  </div>,
  document.getElementById("rd")
);
.demoTitle {
  margin-bottom: 5px;
  font-size: 20px;
  text-decoration: underline;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="rd" />

Explanation

Inline comments added to the snippet above.

Upvotes: 1

Related Questions