1

I came up with the following questing while I was trying to make a TODO app using React.js I was trying to make and update functionality for each task. For that, I made a button which on click, calls a function "update" which calls a function passed as a prop defined in App.js, this function iterates through the tasks array find the one to modify and does its thing, then it sets the new state

App.js

function App() {
      const [taskItems, settaskItems] = useState([]);
      const updateTask = (task,newname) =>{
    const findAndModify=()=>{
      let tasks = [...taskItems] // Why let task=taskItems doesnt work?
      for (let index = 0; index < tasks.length; index++) {
        const t = tasks[index];
        if (t.name === task.name){
          t.name = newname
        }
      }
      return tasks
    }
    settaskItems(findAndModify())
  }
}

My TaskRow component is the following

<TaskRow task={task} key={task.id} toggleTask={toggleTask} updateTask={updateTask}></TaskRow>

Inside the definition of my TaskRow.js component I have the following code

export const TaskRow = (props) => {       
           const update = () => {
               const newname = "hello";
               props.updateTask(props.task, newname);
                };
                return (
    <tr key={props.task.id}>
      <td>{props.task.name}</td>
      <td>
        <input
          type="checkbox"
          checked={props.task.done}
          onChange={() => props.toggleTask(props.task)}
        />
      </td>
      <td>
        <button className="btn btn-success mx-1" onClick={update}>
          Actualizar
        </button>
      </td>
    </tr>
  );
};

the question comes here, if in findAndModify instead of doing let tasks = [...taskItems] I do task=taskItems the description of the updated task does not re-render until another change happens, but if a do a console.log of the data, it indeed, had been modified why is that? how does the [...] operator differs of a regular variable assignment? I've researched about destructuring in JS but nobody talks about some kind of difference between the use of this operator and a regular var assignment in React.js

2 Answers 2

2

The difference between:
(1) method:

let tasks = [...takItems];

(2) method:

tasks = taksItems

is the behavior of javascript with Objects type (for ex. Array) when you assign a variable to an array it creates a reference and not a shallow copy.

So if you use the (2) method and change tasks variable, it will be reflected in tasksItems, if you use the (1) method, you will have 2 independence variables!

React indicates to NEVER mutate a state directly, like you did when using the (2) method and treat it as immutable type.

You can read more about it here

Why we should never update React state directly

Sign up to request clarification or add additional context in comments.

Comments

0

To expand a little bit more, the spread operator [...takItem] makes a shallow copy, which means that it will be a new copy of the variable, but because it is 'shallow' any nested non-primitive data will all be pointers. E.g.,

const tasks = ['a', 'b', { subtask: 1 }]
const shallowCopy = [...tasks]

shallowCopy[0] = 'A'; // won't change the value of tasks
shallowCopy[2].subtasks = 'C'; // does change the values of tasks

console.log(tasks) 
// ['a', 'b', 'C']

In the example above, the third item in the tasks array is non-primitive (also known as "reference" type), so shallowCopy[2] is just a pointer to the same place in memory as tasks[2]. tasks[2] and shallowCopy[2] are both referencing the same piece of data, which is why when you modify shallowCopy[2].subtasks it also modifies tasks[2].subtasks

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.