Home > Blockchain >  how to add and update objects in useState array
how to add and update objects in useState array

Time:10-31

I have a 12 <textarea> elements that I render out in my return using .map. The values in each of them need to be saved to const [answers, setAnswers] = useState([]) but I'm having trouble figuring out a way to do that. An example of what an answer added would look like is: { id: id, answers: ev.target.value }

I need answers to be an array of objects, each object's value being what is written in the <textarea> with the matching key={id} (the id of an answer would be the same as the id of its <textarea>.

Here's all my code:

function AnswerSheet({ questions }) {
  const [answers, setAnswers] = useState();


  return (
    <div className={questions.length ? "" : ""}>
      <ol className="">
        {questions.map(function (q, id) {
          return (
            <li className="" id="" key={id}>
              {q.prompt}
                <span>
                  <textarea
                    className=""
                    rows={1}
                    onChange={(ev) => {
                       // a line here I assume to check if answer exists with this id, and either update or add {id: id, answer: ev.target.value} with setAnswers()
                    }}
                  ></textarea>
                </span>
            </li>
          );
        })}
      </ol>
    </div>
  );
}
export default AnswerSheet;

I messed around with different ways of achieving this, but none worked without deleting previous answers. I need a way to add a new answer, but once an answer exists with an id, I need a way to update that answer by presumably finding and matching the id of the <textarea> to the id of the answer and updating the answer text.

CodePudding user response:

I would suggest using a dictionary instead of an array as it already has a key and a value, which is what you're looking for. Doing it with an array is possible but you would have to iterate through the array until you find an item with the same id, then you make a copy of the array (let ans = [...answers]), modify the item at that particular index and use setAnswers to set it. Here's a potential solution using dictionary:

import { useCallback, useState } from "react";

function AnswerSheet({ questions }) {
  const [answers, setAnswers] = useState({});

  const onTextChange = useCallback(
    (id, text) => {
      let ans = { ...answers };
      ans[id] = text;
      setAnswers(ans);
    },
    [answers]
  );

  return (
    <div className={questions.length ? "" : ""}>
      <ol className="">
        {questions.map(function (q, id) {
          return (
            <li className="" id="" key={id}>
              {q.prompt}
              <span>
                <textarea
                  className=""
                  rows={1}
                  onChange={(ev) => {
                    onTextChange(id, ev.target.value);
                    // a line here I assume to check if answer exists with this id, and either update or add {id: id, answer: ev.target.value} with setAnswers()
                  }}
                ></textarea>
              </span>
            </li>
          );
        })}
      </ol>
      {//Added this just to show they change independently
      }
      {Object.entries(answers).map(([key, value]) => (
        <div key={key}>
          {key}. {value}
        </div>
      ))}
    </div>
  );
}
export default AnswerSheet;
  • Related