--- id: return title: Returning new data from producers ---
egghead.io lesson 9: Returning completely new state
Hosted on egghead.io
It is not needed to return anything from a producer, as Immer will return the (finalized) version of the `draft` anyway. However, it is allowed to just `return draft`. It is also allowed to return arbitrarily other data from the producer function. But _only_ if you didn't modify the draft. This can be useful to produce an entirely new state. Some examples: ```javascript const userReducer = produce((draft, action) => { switch (action.type) { case "renameUser": // OK: we modify the current state draft.users[action.payload.id].name = action.payload.name return draft // same as just 'return' case "loadUsers": // OK: we return an entirely new state return action.payload case "adduser-1": // NOT OK: This doesn't do change the draft nor return a new state! // It doesn't modify the draft (it just redeclares it) // In fact, this just doesn't do anything at all draft = {users: [...draft.users, action.payload]} return case "adduser-2": // NOT OK: modifying draft *and* returning a new state draft.userCount += 1 return {users: [...draft.users, action.payload]} case "adduser-3": // OK: returning a new state. But, unnecessary complex and expensive return { userCount: draft.userCount + 1, users: [...draft.users, action.payload] } case "adduser-4": // OK: the immer way draft.userCount += 1 draft.users.push(action.payload) return } }) ``` _Note: It is not possible to return `undefined` this way, as it is indistinguishable from *not* updating the draft! Read on..._ ## Producing `undefined` using `nothing` So, in general, one can replace the current state by just `return`ing a new value from the producer, rather than modifying the draft. There is a subtle edge case however: if you try to write a producer that wants to replace the current state with `undefined`: ```javascript produce({}, draft => { // don't do anything }) ``` Versus: ```javascript produce({}, draft => { // Try to return undefined from the producer return undefined }) ``` The problem is that in JavaScript a function that doesn't return anything also returns `undefined`! So immer cannot differentiate between those different cases. So, by default, Immer will assume that any producer that returns `undefined` just tried to modify the draft. However, to make it clear to Immer that you intentionally want to produce the value `undefined`, you can return the built-in token `nothing`: ```javascript import produce, {nothing} from "immer" const state = { hello: "world" } produce(state, draft => {}) produce(state, draft => undefined) // Both return the original state: { hello: "world"} produce(state, draft => nothing) // Produces a new state, 'undefined' ``` N.B. Note that this problem is specific for the `undefined` value, any other value, including `null`, doesn't suffer from this issue. ## Inline shortcuts using `void`
egghead.io lesson 10: Avoid accidental returns by using _void_
Hosted on egghead.io
Draft mutations in Immer usually warrant a code block, since a return denotes an overwrite. Sometimes that can stretch code a little more than you might be comfortable with. In such cases, you can use javascripts [`void`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void) operator, which evaluates expressions and returns `undefined`. ```javascript // Single mutation produce(draft => void (draft.user.age += 1)) // Multiple mutations produce(draft => void ((draft.user.age += 1), (draft.user.height = 186))) ``` Code style is highly personal, but for code bases that are to be understood by many, we recommend to stick to the classic `draft => { draft.user.age += 1}` to avoid cognitive overhead.