Search code examples
javascriptarraysreactjsindexof

How to instantly update react state after replacing the value from array


I have a function which gets the user input and update the array if the same key is available already. with the help of this article

This is how it looks;

  const handleClickYes = (question) => {
    // find if question is in the data array
    const hasQuestion = data.find(({ parentId }) => question.id === parentId)
    
    const indexOfQuestion = data.indexOf(hasQuestion)
    
    if (hasQuestion) {
      // update the value with specific selected index in the array. 
      data[indexOfQuestion] = { question: question.if_yes, parentId: question.id, userChoice: 'YES', child: [] }
    } else {
      setData((data) => data.concat({ question: question.if_yes, parentId: question.id, userChoice: 'YES', child: [] }))
    }
    localStorage.setItem('deviceReport', JSON.stringify(data))
  }

I'm using localStorage to persist the state

  const deviceReport = localStorage.getItem('deviceReport') ? JSON.parse(localStorage.getItem('deviceReport')) : []
  const [data, setData] = useState(deviceReport)

Here the problem is if I use setData then it updates instantly but on replacing the array at this part

data[indexOfQuestion] = { question: question.if_yes, parentId: question.id, userChoice: 'YES', child: [] }

it dosent update the mapped data on JSX portion. How can I configure it to update it happen in setState. ? Or any other better option to update the array.


Solution

  • You're not calling setState() within the first half of your if block. Also, never mutate state directly. Make a mutable copy, like so:

    const handleClickYes = (question) => {
      // find if question is in the data array
      const hasQuestion = data.find(({ parentId }) => question.id === parentId);
    
      const indexOfQuestion = data.indexOf(hasQuestion);
    
      // copy data to mutable object
      let newData = [...data];
      if (hasQuestion) {
        // update the value with specific selected index in the array.
        newData[indexOfQuestion] = {
          question: question.if_yes,
          parentId: question.id,
          userChoice: "YES",
          child: [],
        };
      } else {
        //   concat existing data with a new question
        newData = [
          ...newData,
          {
            question: question.if_yes,
            parentId: question.id,
            userChoice: "YES",
            child: [],
          },
        ];
      }
      localStorage.setItem("deviceReport", JSON.stringify(newData));
      setData(newData);
    };