前言
immer是一个第三方模块,可以更加方便的处理不可变状态,其核心实现是利用ES6的proxy。
下载
npm
npm install immer use-immer
yarn
yarn add immer use-immer
immer基本使用
语法:
produce(currentState, recipe: (draftState) => void | draftState, ?PatchListener): nextState
- currentState: 被操作对象的最初状态
- draftState: 根据 currentState 生成的草稿状态,它是currentState的代理,对draftState 所做的任何修改都将被记录并用于生成 nextState。在此过程中,currentState 将不受影响
- nextState:根据draftState 生成的最终状态
- produce: 用来生成 nextState 或 producer 的函数
- producer: 生产者 通过 produce 生成,用来生产nextState ,每次执行相同的操作
- recipe: 生产机器 用来操作draftState 的函数
- PatchListener可有可无的
与useState对比
处理数组
需求:点击按钮添加一行数据
useState实现
import { useState } from "react"
function App() {
const [list, setList] = useState([
{ id: 1, text: "aaa" },
{ id: 2, text: "bbb" },
{ id: 3, text: "ccc" },
])
const handleClick = () => {
setList([...list,{ id: 4, text: "ddd" }])
}
return (
<div>
<button onClick={handleClick}>点击添加</button>
<ul>
{list.map((item) => {
return <li key={item.id}>{item.text}</li>
})}
</ul>
</div>
)
}
useImmer实现
import { useImmer } from "use-immer"
function App() {
const [list, setList] = useImmer([
{ id: 1, text: "aaa" },
{ id: 2, text: "bbb" },
{ id: 3, text: "ccc" },
])
const handleClick = () => {
setList((draft) => {
draft.push({ id: 4, text: "ddd" })
})
}
return (
<div>
<button onClick={handleClick}>点击添加</button>
<ul>
{list.map((item) => {
return <li key={item.id}>{item.text}</li>
})}
</ul>
</div>
)
}
处理对象
需求:点击将"小明" 变成 “大明”
useState实现
import { useState } from "react"
import { cloneDeep } from "lodash"
function App() {
const [userInfo, setUserInfo] = useState(
{
name:{
firstname:"小",
lastname:"明"
},
age:23
}
)
const handleClick = () => {
// 方法一:
setUserInfo({
...userInfo,
name:{
...userInfo.name,
firstname:"大"
}
})
// 方法二:也可以使用lodash
const cloneUserInfo = cloneDeep(userInfo)
cloneUserInfo.name.firstname = "大"
setUserInfo(cloneUserInfo)
}
return (
<div>
<button onClick={handleClick}>修改name</button>
<div>{ JSON.stringify(userInfo) }</div>
</div>
)
}
useImmer实现
import { useImmer } from "use-immer"
function App() {
const [userInfo, setUserInfo] = useImmer(
{
name:{
firstname:"小",
lastname:"明"
},
age:23
}
)
const handleClick = () => {
setUserInfo((draft) => {
draft.name.firstname = "大"
})
}
return (
<div>
<button onClick={handleClick}>修改name</button>
<div>{ JSON.stringify(userInfo) }</div>
</div>
)
}