https://immerjs.github.io/immer/zh-CN/produce
在 React 中,状态(state)是不可变的,任何状态的更新都需要生成新的状态对象。Immer 通过 produce
函数简化了这一过程,允许开发者以类似于修改可变对象的方式去更新状态,而实际上它会自动创建新的状态对象,从而保持了状态的不可变性
Produce
produce(currentState, recipe: (draftState) => void): nextState
-
currentState:被操作对象的初始状态
-
draftState:currentState代理,修改的draftState不会影响currentState
-
nextState:根据 draftState 生成的最终状态
-
produce 生产 用来生成 nextState 或 producer 的函数
-
producer 生产者 通过 produce 生成,用来生产 nextState ,每次执行相同的操作
(baseState, ...arguments) => resultState
-
recipe 生产机器 用来操作 draftState 的函数
柯里化 producers
import produce from 'immer';
const toggle = produce((draft) => {
const todo = draft.find(item => item.id === id)
todo.done = !todo.done
})
const current = [
{
id:1,
name:'你好',
done:false
},
{
id:2,
name:'汽车',
done:false
},
{
id:2,
name:'吃饭',
done:false
},
]
const nextState = toggle(current, 2)
console.log(nextState); //id:2的done为true
console.log(current); //id:2的done为false,不会修改原始数据
React & Immer
useState + Immer
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 简化useState + Immer
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
});
});
}, []);
useReducer + Immer
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 等于useReducer+immer
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 */ ]
);