它和immutable相似的,实现了操作对象的数据共享,可以优化性能。此库是由mobx作用开发出来的,还得过2019年react开源大奖,它实现的原理使用es6的Proxy完成的。小巧,没有像immutable哪样有新数据类型,而是使用js类型。
安装
yarn add immer@9
我在之前对state原始数据类型如果是一个对象的话,那么操作起来就需要返回一个新的对象,通过过响应式的方式修改:
以前
//很麻烦
state={
num:1000
}
count = ()=>{
this.setState((state)=>({num:state.num+1}),()=>{
console.log(this.state.num);
});
}
原理就是:把源数据使用Proxy进行代理处理,后面就可以精准的去找到变化的数据
import { produce } from 'immer'
import React from 'react';
// 把源数据使用Proxy进行代理处理,后面就可以精准的去找到变化的数据
import { produce } from 'immer'
const state = {
num :100
}
// 进行代理后,并修改。 draft就是代理对象,它就是state代理对象
const newstart = produce(state,draft=>{
draft.num++
})
console.log(newstart.num);
const App = () => {
return (
<div>
</div>
);
}
export default App;
使用immer,它进行proxy代理,源数据中只有变化的了的数据它才更新,没有变化则共享,提高性能
import { produce } from 'immer'
const baseState = {
arr: [1, 2, 3],
obj: { id: 1, name: '张三' }
}
// 使用immer,它进行proxy代理,源数据中只有变化的了的数据它才更新,没有变化则共享,提高性能
const newState = produce(baseState, draft => {
draft.arr.push(4);
})
// 当前只修改数组,对象没有修改,共享
console.log('arr', newState.arr === baseState.arr) // false
console.log('obj', newState.obj === baseState.obj) // true
const App = () => {
return (
<div>
</div>
);
}
export default App;
import React, { Component } from 'react';
import { produce } from 'immer'
class App extends Component {
state={
num:1000
}
count = ()=>{
// this.setState(state => ({ count: state.count + 1 }))
//第一个参数就隐式传递给了代理对象,只需要第二个函数参数即可去执行
//不用返回,返加不允许,draft它是一个代理对象,修改后,它能监听到数据的变化,更新视图
this.setState(produce(draft=>{
draft.num++
}))
}
render() {
return (
<div>
<h1>{this.state.num}</h1>
<button onClick={this.count}>+++++</button>
</div>
);
}
}
export default App;
数值类为object的更加方便了操作。一下子变的简单了
import React, { Component } from 'react';
import { produce } from 'immer'
class App extends Component {
state={
carts: [
{ id: 1, name: 'aa', num: 1 },
{ id: 2, name: 'bb', num: 2 }
]
}
}
render() {
return (
<div>
{
<ul>
{this.state.carts.map((item,index)=>(
<li key={index}>
<span>{item.name}</span>
<span>_____</span>
<span>{item.num}_____<button onClick={()=>{
this.setState(produce(draft=>{
draft.carts[index].num++
}))
}}>+++</button></span>
</li>
))}
</ul>
}
</div>
);
}
}
export default App;
变量如果是普通的数字,而proxy代理的是对象,proxy代理的是对象
如果它是一个普通值,没有必要使用immer来完成优化操作,可以使用返回值。
import React, { useState } from 'react'
import { produce } from 'immer'
const App = () => {
// 普通的数字,不是proxy代理,proxy代理的是对象
// 如果它是一个普通值,没有必要使用immer来完成优化操作
let [count, setCount] = useState(100)
// 对象类型才是使用immer工作的场景
let [carts, setCarts] = useState([
{ id: 1, name: 'aa', num: 1 },
{ id: 2, name: 'bb', num: 2 }
])
return (
<div>
<h1>{count}</h1>
<button onClick={e=>{setCount(v=>v+1)}}>+++</button>
<button onClick={e=>{setCount(produce(deaft=>{return deaft+1}))}}>+++</button>
</div>
);
}
export default App;
不能返回,写上去感觉就像在vue的感觉
import React, { useState } from 'react'
import { produce } from 'immer'
const App = () => {
// 普通的数字,不是proxy代理,proxy代理的是对象
// 如果它是一个普通值,没有必要使用immer来完成优化操作
let [count, setCount] = useState(100)
// 对象类型才是使用immer工作的场景
let [carts, setCarts] = useState([
{ id: 1, name: 'aa', num: 1 },
{ id: 2, name: 'bb', num: 2 }
])
return (
<div>
<h1>{count}</h1>
<button onClick={e=>{setCount(v=>v+1)}}>+++</button>
<button onClick={e=>{setCount(produce(deaft=>{return deaft+1}))}}>+++</button>
<hr />
{/* 之前写法 */}
<button onClick={e=>{setCarts(v => [...v,{ id: Date.now(), num: 1, name: 'aaaa--' + Date.now() }])}}>添加一个对象</button>
{/* immer写法 */}
<button onClick={e=>{setCarts(produce(draft=>{
draft.push({ id: Date.now(), num: 1, name: 'aaaa--' + Date.now() })
}))}}>添加一个对象</button>
<hr />
{
<ul>
{
carts.map((item,index)=>(
<li key={item.id}>
<span>{item.name}</span>
<span>---</span>
<span>
{item.num} --
<button onClick={e=>{
/* 之前的写法 */
setCarts(v=>{
let data = JSON.parse(JSON.stringify(v));//深复制
data[index].num++;
return data
})
}}>+++</button>
<button onClick={e=>{
/* immer优化的写法 */
// 不能返回,写上去感觉就像在vue的感觉
setCarts(produce(draft=>{
draft[index].num++
}))
}}>+++</button>
<button onClick={e=>{
setCarts(produce(draft=>{
draft.splice(index,1)
}))
}}>---</button>
</span>
</li>
))
}
</ul>
}
</div>
);
}
export default App;
操作数据无需深复制,提升性能
import { createStore } from 'redux'
import { produce } from 'immer'
const initState = {
count: 100
}
const reducer = (state = initState, { type, payload }) => {
if ('add' === type) {
return { ...state, count: state.count + payload }
}
return state
}
const reducer = produce((draft, { type, payload }) => {
// 写法就和vuex中的mutation中的写法一样的,简化了
// 操作数据无需深复制,提升性能
//第二个参数就是代理对象
if ('add' === type) draft.count += payload
}, initState)
export default createStore(reducer)
app.js范例:
import React from 'react';
import {useSelector,useDispatch} from "react-redux"
const App = () => {
const count = useSelector(state=>state.count);
const dispatch = useDispatch()
return (
<div>
<h1>{count}</h1>
<hr />
<button onClick={e=>{dispatch({type:"add",payload:2})}}>+++</button>
</div>
);
}
export default App;