Home > OS >  In React object updates but does not pass updated object to next function
In React object updates but does not pass updated object to next function

Time:04-15

I am using React and have the following object:

const [records, setRecords] = useState(
    [
      {id: 1, correct: false},
      {id: 2, correct: false},
      {id: 3, correct: false},
      {id: 4, correct: false},
      {id: 5, correct: false}
    ]);

To update the object I have the following:

const onCorrectAnswerHandler = (id, correct) => {
    setRecords(
      records.map((record) => {
        if (record.id === id) {
          return { id: id, correct: true };
        } else {
          return record;
        }
      })
    );
  }

Here's the problem:

I want to run another function called isComplete after it but within the Handler function, that uses the changed records object, but it appears to use the original unchanged 'records' object (which console.log confirms).

e.g.

const onCorrectAnswerHandler = (id, correct) => {
    setRecords(
      records.map((record) => {
        if (record.id === id) {
          return { id: id, correct: true };
        } else {
          return record;
        }
      })
    );
    isComplete(records);
  }

Console.log(records) confirms this. Why does it not use the updated records since the isComplete function runs after the update, and how can I get it to do this?

CodePudding user response:

Try renaming the function as React sees no change in the object and likewise when you are using an array or object in a state. Try to copy them out by storing them in a new variable.

setRecords(
  const newRecords = records.map((record) => {
    if (record.id === id) {
        return { id: id, correct: true };
      } else {
        return record;
      }
    })
   //seting this now triggers an update
   setRecords(newRecords);
);

Then as per react documentation it's better to listen to changes with lifecycle methods and not setting state immediately after they are changed because useState is asynchronous.

so use useEffect to listen to the changes to set is Complete

useEffect(() => {
  isComplete(records)
}, [records])

I hope this helps you?

CodePudding user response:

This is due to the fact that setState is not actually synchronous. The stateful value is not updated immediately when setState is called, but on the next render cycle. This is because React does some behind the scenes stuff to optimise re-renders.

There are multiple approaches to get around this, one such approach is this:

If you need to listen to state updates to run some logic you can use the useEffect hook.

useEffect(() => {
  isComplete(records)
}, [records])

This hook is pretty straightforward. The first argument is a function. This function will run each time if one of the variables in the dependency array updates. In this case it will run each time records update.

CodePudding user response:

You can modify above function onCorrectAnswerHandler to hold the updated records in temporary variable and use to update state and call isComplete func

const onCorrectAnswerHandler = (id, correct) => {
    let _records = records.map((record) => {
        if (record.id === id) {
            return {
                id: id,
                correct: true
            };
        } else {
            return record;
        }
    })
    setRecords(_records);
    isComplete(_records);
}

CodePudding user response:

try this please.

  const onCorrectAnswerHandler = (id) => {
    records.forEach(r =>{
      if(r.id == id)  r.correct=true; 
    });
     setRecords([...records]);
  }
  • Related