Doorgaan naar hoofdinhoud

Nieuwe gegevens retourneren vanuit producers

[Onofficiële Beta-vertaling]

Deze pagina is vertaald door PageTurner AI (beta). Niet officieel goedgekeurd door het project. Een fout gevonden? Probleem melden →

egghead.io lesson 9: Returning completely new state

Het is niet nodig om iets terug te geven vanuit een producer, omdat Immer toch de (gefinaliseerde) versie van de draft retourneert. Maar het is wel toegestaan om simpelweg return draft te gebruiken.

Je mag ook willekeurige andere data retourneren vanuit de producer-functie. Maar alleen als je de draft niet hebt aangepast. Dit kan handig zijn om een compleet nieuwe staat te produceren. Enkele voorbeelden:

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
}
})

Let op: Het is niet mogelijk om op deze manier undefined terug te geven, omdat dit niet te onderscheiden is van geen wijziging aan de draft! Lees verder...

undefined produceren met nothing​

Over het algemeen kun je de huidige staat vervangen door simpelweg een nieuwe waarde te returnen vanuit de producer, in plaats van de draft aan te passen. Er is echter een subtiel randgeval: wanneer je een producer wilt schrijven die de huidige staat vervangt door undefined:

produce({}, draft => {
// don't do anything
})

Tegenover:

produce({}, draft => {
// Try to return undefined from the producer
return undefined
})

Het probleem is dat in JavaScript een functie die niets retourneert ook undefined teruggeeft! Immer kan dus geen onderscheid maken tussen deze situaties. Standaard gaat Immer er daarom vanuit dat elke producer die undefined retourneert, probeerde de draft te wijzigen.

Om Immer duidelijk te maken dat je bewust de waarde undefined wilt produceren, kun je het ingebouwde token nothing retourneren:

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. Dit probleem is specifiek voor de undefined waarde; elke andere waarde, inclusief null, heeft hier geen last van.

Tip: om nothing te kunnen retourneren vanuit een recipe in TypeScript, moet het type van state undefined als waarde accepteren.

Inline snelkoppelingen met void​

egghead.io lesson 10: Avoid accidental returns by using _void_

Draft-mutaties in Immer vereisen meestal een codeblok, omdat een return een overschrijving aangeeft. Dit kan de code soms wat uitgebreider maken dan gewenst.

In zulke gevallen kun je JavaScripts void-operator gebruiken, die expressies evalueert en undefined retourneert.

// Single mutation
produce(draft => void (draft.user.age += 1))

// Multiple mutations
produce(draft => void ((draft.user.age += 1), (draft.user.height = 186)))

Codestijl is persoonlijk, maar voor codebases die door velen begrepen moeten worden, raden we aan om de klassieke draft => { draft.user.age += 1} aan te houden om cognitieve overhead te voorkomen.