React & Immer
Deze pagina is vertaald door PageTurner AI (beta). Niet officieel goedgekeurd door het project. Een fout gevonden? Probleem melden →
egghead.io lesson 8: Using Immer with _useState_. Or: _useImmer_
useState met Immer​
De useState hook gaat ervan uit dat alle state die erin wordt opgeslagen als onveranderlijk wordt behandeld. Diepgaande updates in de state van React-componenten kunnen aanzienlijk worden vereenvoudigd door Immer te gebruiken. Het volgende voorbeeld laat zien hoe je produce kunt combineren met useState, en is uit te proberen op CodeSandbox.
import React, { useCallback, useState } from "react";
import {produce} from "immer";
const TodoList = () => {
const [todos, setTodos] = useState([
{
id: "React",
title: "Learn React",
done: true
},
{
id: "Immer",
title: "Try Immer",
done: false
}
]);
const handleToggle = useCallback((id) => {
setTodos(
produce((draft) => {
const todo = draft.find((todo) => todo.id === id);
todo.done = !todo.done;
})
);
}, []);
const handleAdd = useCallback(() => {
setTodos(
produce((draft) => {
draft.push({
id: "todo_" + Math.random(),
title: "A new todo",
done: false
});
})
);
}, []);
return (<div>{*/ See CodeSandbox */}</div>)
}
useImmer​
Omdat alle state-updaters hetzelfde patroon volgen waarbij de updatefunctie in produce is verpakt, kun je bovenstaande vereenvoudigen door het use-immer pakket te gebruiken. Dit verpakt updaterfuncties automatisch in produce:
import React, { useCallback } from "react";
import { useImmer } from "use-immer";
const TodoList = () => {
const [todos, setTodos] = useImmer([
{
id: "React",
title: "Learn React",
done: true
},
{
id: "Immer",
title: "Try Immer",
done: false
}
]);
const handleToggle = useCallback((id) => {
setTodos((draft) => {
const todo = draft.find((todo) => todo.id === id);
todo.done = !todo.done;
});
}, []);
const handleAdd = useCallback(() => {
setTodos((draft) => {
draft.push({
id: "todo_" + Math.random(),
title: "A new todo",
done: false
});
});
}, []);
// etc
Bekijk de volledige demo op CodeSandbox.
useReducer met Immer​
Net als useState combineert useReducer naadloos met Immer, zoals gedemonstreerd in deze CodeSandbox:
import React, {useCallback, useReducer} from "react"
import {produce} from "immer"
const TodoList = () => {
const [todos, dispatch] = useReducer(
produce((draft, action) => {
switch (action.type) {
case "toggle":
const todo = draft.find(todo => todo.id === action.id)
todo.done = !todo.done
break
case "add":
draft.push({
id: action.id,
title: "A new todo",
done: false
})
break
default:
break
}
}),
[
/* initial todos */
]
)
const handleToggle = useCallback(id => {
dispatch({
type: "toggle",
id
})
}, [])
const handleAdd = useCallback(() => {
dispatch({
type: "add",
id: "todo_" + Math.random()
})
}, [])
// etc
}
useImmerReducer​
...wat opnieuw iets korter kan met useImmerReducer uit het use-immer pakket (demo):
import React, { useCallback } from "react";
import { useImmerReducer } from "use-immer";
const TodoList = () => {
const [todos, dispatch] = useImmerReducer(
(draft, action) => {
switch (action.type) {
case "toggle":
const todo = draft.find((todo) => todo.id === action.id);
todo.done = !todo.done;
break;
case "add":
draft.push({
id: action.id,
title: "A new todo",
done: false
});
break;
default:
break;
}
},
[ /* initial todos */ ]
);
//etc
Redux met Immer​
Redux met Immer wordt uitgebreid behandeld in de documentatie van Redux Toolkit. Voor Redux zonder Redux Toolkit kun je dezelfde truc toepassen als bij useReducer hierboven: verpak de reducer-functie in produce, en je kunt veilig de draft muteren!
Bijvoorbeeld:
import {produce} from "immer"
// Reducer with initial state
const INITIAL_STATE = [
/* bunch of todos */
]
const todosReducer = produce((draft, action) => {
switch (action.type) {
case "toggle":
const todo = draft.find(todo => todo.id === action.id)
todo.done = !todo.done
break
case "add":
draft.push({
id: action.id,
title: "A new todo",
done: false
})
break
default:
break
}
})