15

I am using immer to transform react/redux state. Can I also use immer to just deep copy an object without transforming it?

import produce, {nothing} from "immer"
const state = {
 hello: "world"
}
produce(state, draft => {})
produce(state, draft => undefined)
// Both return the original state: { hello: "world"}

This is from the official immer README. Does this mean that passing an empty function to produce returns a deep copy of the original state or actually the original state?

Thank you very much for your help :)!

asked Mar 5, 2019 at 9:08

3 Answers 3

19

This is easily testable with

import { produce } from 'immer'
const state = {
 hello: 'world',
}
const nextState = produce(state, draft => {})
nextState.hello = 'new world'
console.log(state, nextState)

which outputs

Object { hello: "new world" }
Object { hello: "new world" }

which means that it does NOT create a deep copy of an object.

UPDATE:

So I got interested and tested out the library a lot and here are my findings.

The code snippet I wrote above is simply an optimisation in the library which returns the old state if no changes are made. However, if you make some changes, then the library starts functioning as intended and the mutation later is made impossible. That is,

const state = {
 hello: 'world',
}
const nextState = produce(state, draft => {
 draft.hello = 'new world';
})
nextState.hello = 'newer world';
console.log(state, nextState)

will result in an error: TypeError: "world" is read-only

Which means that your newState is immutable and you can no longer perform mutations on it.

Another rather interesting thing I found is that immer fails when using class instances. That is,

class Cls {
 prop = 10;
}
const instance = new Cls();
const obj = {
 r: instance,
};
const newObj = produce(obj, draft => {
 draft.r.prop = 15;
});
console.log(obj, newObj);

results in

r: Object { prop: 15 }
r: Object { prop: 15 }

So to get back to the initial question, can you get a deep copy of the initial Object by changing nothing in the draft. No you cannot, and even if you did (by changing a property created just to fool immer perhaps), the resultant cloned object will be immutable and not really helpful.

answered Mar 5, 2019 at 9:31
Sign up to request clarification or add additional context in comments.

3 Comments

I had used class instance and is deep updating the state using immer. I now got my answer for why my setState is not rerendering the Application on deep updating with immer?
The class thing could be because it's missing an [immerable] = true property. I don't know if this feature was added after you posted your answer.
> the resultant cloned object will be immutable and not really helpful. **** Why is it not really helpful if the end goal is to have immutable object for performance? In other words, many times we clone so that we can avoid mutation on the original object from triggering side-effect, like expensive re-rendering elsewhere that we did not expect.
2

Solution : The Immer's produce only provides a new deep cloned object on updation. you can create your own produce function that behaves just like that of immer's produce but gives a cloned object everytime using loadash

import _ from 'lodash';
export default function produceClone(object, modifyfunction) {
 let objectClone = _.cloneDeep(object);
 if (!modifyfunction) return objectClone;
 modifyfunction(objectClone);
 return objectClone;
 }

This will give you a deepCloned(or deep copied) object everytime, irrespective of whether you modify the object or not.

Simon_Weaver
147k92 gold badges689 silver badges724 bronze badges
answered May 30, 2021 at 14:11

1 Comment

Just use lodash without immer here in this example, no need to do it this way why i only need a deep clone, just cloneDeep will do the job here
0

This is an answer I found on Github and is much better than the selected answer. https://github.com/immerjs/immer/issues/619#issuecomment-644393613

cloneDeep will always fully clone your entire state. This causes two fundamental problems which makes it quite unusable to use with react for any slightly significant amount of data:

  1. deepClone is very expensive. You have a collection of 100 items? All those items will continuously be retreated on every update. Hitting both the performance and the garbage collector badly
  2. deepClone can't leverage memoization, because the "same" objects will not be refererrentially equal after every update. So it means that react will always need to rerender all your components. Which basically kills all benefits that immutability would offer you in the first place.

In other words, deepClone, unlike produce, doesn't offer structural sharing of all the unchanged parts of your state after an update

answered Feb 13, 2025 at 17:53

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.