Pitfalls
#
Performance tipsFor performance tips, see Performance Tips.
#
Don't reassign the recipe argumentNever reassign the draft
argument (example: draft = myCoolNewState
). Instead, either modify the draft
or return a new state. See Returning data from producers.
#
Immer only supports unidirectional treesImmer assumes your state to be a unidirectional tree. That is, no object should appear twice in the tree, there should be no circular references. There should be exactly one path from the root to any node of the tree.
undefined
from a producer#
Never explicitly return It is possible to return values from producers, except, it is not possible to return undefined
that way, as it is indistinguishable from not updating the draft at all! If you want to replace the draft with undefined
, just return nothing
from the producer.
#
Don't mutate exotic objectsImmer does not support exotic objects such as window.location.
#
Classes should be made draftable or not mutatedYou will need to enable your own classes to work properly with Immer. For docs on the topic, check out the section on working with complex objects.
#
Only valid indices and length can be mutated on ArraysFor arrays, only numeric properties and the length
property can be mutated. Custom properties are not preserved on arrays.
#
Data not originating from the state will never be draftedNote that data that comes from the closure, and not from the base state, will never be drafted, even when the data has become part of the new draft.
#
Immer patches are not necessarily optimalThe set of patches generated by Immer should be correct, that is, applying them to an equal base object should result in the same end state. However Immer does not guarantee the generated set of patches will be optimal, that is, the minimum set of patches possible.
#
Always use the result of nested producersNested produce
calls are supported, but note that produce
will always produce a new state, so even when passing a draft to a nested produce, the changes made by the inner produce won't be visible in the draft that was passed it, but only in the output that is produced. In other words, when using nested produce, you get a draft of a draft and the result of the inner produce should be merged back into the original draft (or returned). For example produce(state, draft => { produce(draft.user, userDraft => { userDraft.name += "!" })})
won't work as the output if the inner produce isn't used. The correct way to use nested producers is:
#
Drafts aren't referentially equalDraft objects in Immer are wrapped in Proxy
, so you cannot use ==
or ===
to test equality between an original object and its equivalent draft (eg. when matching a specific element in an array). Instead, you can use the original
helper:
If possible, it's recommended to perform the comparison outside the produce
function, or to use a unique identifier property like .id
instead, to avoid needing to use original
.