Home > Mobile >  How can I create a separate backup state in React, so that I can edit one set of data but reset to t
How can I create a separate backup state in React, so that I can edit one set of data but reset to t

Time:10-17

I am presenting my user with an editable table pre-populated with data, and want to include a 'Discard Changes' button that will call the handleReset() function to restore the 'active' set of data (an array of objects) to it's original state.

The approach I've taken is to read the data into a variable called 'dataBackup', and also into a state variable called 'dataWorking'. The idea is that user edits will be applied to dataWorking, while dataBackup will be left unchanged and is available for use to reset dataWorking if needed. However when the table is edited, changes are simultaneously applied to both variables!

I'm quite new to React and am not understanding this behavior. I'm also not certain my chosen approach is the best way to handle this functionality, because I haven't been able to find any similar examples out there. Would appreciate some pointers, and have added my sample code belong to demonstrate what's happening.

import {useState} from 'react';
  
const budgetData = 
      [ 
        {   index: 0, category: 'Housing',   item: 'Mortgage',  amount: 650.99 },
        {   index: 1, category: 'Housing',   item: 'Insurance', amount: 275.50 }, 
        {   index: 2, category: 'Utilities', item: 'Hydro',     amount:  70.00 }      
      ];

function UpdateBudget()  {
    const  dataBackup = [...budgetData];
    const [dataWorking, setDataWorking ] = useState(budgetData); 

    const handleChange = ( (e, row) => {
      let selectedData = [...dataWorking];
      const {name, value} = e.target;
      selectedData[row][name] = value;
      setDataWorking(selectedData);
    });

    const handleReset = ( (e) => {
      setDataWorking(dataBackup);
    });


    return  (
      <div>
        <table>
          <thead>
            <tr>
              <th>Category</th> <th>Item</th> <th>Amount</th>
            </tr>
          </thead>

          <tbody>
              { dataWorking.map( (row) =>  (
                  <tr key={row.index}>
                    <td> <input value={row.category} name="category" onChange={(e) => handleChange(e, row.index)}/> </td>
                    <td> <input value={row.item    } name="item"     onChange={(e) => handleChange(e, row.index)}/> </td>
                    <td> <input value={row.amount  } name="amount"   onChange={(e) => handleChange(e, row.index)}/> </td>
                  </tr>
                ))
              }
          </tbody>
        </table>
        <div> 
            <button onClick={ (e) => handleReset (e)}> Discard Changes </button>
        </div>
        <div style={{ marginTop: 20, fontSize: 10 }}> * budgetData  {budgetData.length}  * {JSON.stringify(budgetData)}  </div> 
        <div style={{ marginTop: 20, fontSize: 10 }}> * dataWorking {dataWorking.length} * {JSON.stringify(dataWorking)} </div> 
        <div style={{ marginTop: 20, fontSize: 10 }}> * dataBackup  {dataBackup.length}  * {JSON.stringify(dataBackup)}  </div>
      </div>
    );
}
   
export default UpdateBudget;

CodePudding user response:

You are seeing dataBackup updated after your state change is because you are copying the objects inside the array by reference. If you want to have a totally unreferenced copy of budgetData, the simplest solution is

would be to use JSON methods (but I recommend researching what deep copying an object is):

const  dataBackup = JSON.parse(JSON.stringify(budgetData))

Generally, best practice to store values that will not cause UI rerenders is by using useRef:

const  dataBackup = React.useRef(JSON.parse(JSON.stringify(budgetData)))
// then access it like that
dataBackup.current

Another thing, inside your handleChange you are actually mutating the state, which should be avoided:

selectedData[row][name] = value;

Ideally, you should splice and spread those objects so you are not modifying the state directly, or use some deep copy method.

  • Related