What is meant by "Data not originating from the state will never be drafted" in immer

91 Views Asked by At

I'm confused by this section of the immer docs. I created a simpler example to test the same principle, i.e. to add some new object to the draft data structure and then modify it. Which according to the docs should also modify the original data structure:

import { produce } from "immer";

function print(obj) {
  console.log(JSON.stringify(obj));
}

var todos = [
  { id: 0, done: false },
  { id: 1, done: false }
];

function onReceiveTodo(todo) {
  return produce(todos, draft => {
    draft[1] = todo;
    draft[1].done = true;
  });
}

let nextTodos = onReceiveTodo({ id: 3, done: false });
print(todos);
print(nextTodos);

// [{"id":0,"done":false},{"id":1,"done":false}] // todos
// [{"id":0,"done":false},{"id":3,"done":true}] // nextTodos

But this seems to work.

Could someone please explain this pitfall in a bit more detail?

Note: I also tried to use the exact same example that was in the docs, but was confused about what the data structure todos is supposed to look like. Since draft is bound to the original version of todos, this line: draft.todos[todo.id] = todo suggests that we have something like todos = {todos: {0: {done: false}, 1: {done: false},...}, but todo.id suggests that a todo object contains the id.

1

There are 1 best solutions below

0
On BEST ANSWER

It's about "if you pass and mutate an object inside produce it is in fact mutated".

Could someone please explain this pitfall in a bit more detail?

Basically when you do:

let nextTodos = onReceiveTodo({ id: 3, done: false });

The original object can be changed. Consider instead:

const todo = { id: 3, done: false };
let nextTodos = onReceiveTodo(todo);
todo.done; // true, this object was mutated outside of Immer