它和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);
});
}
immer簡單的使用
原理就是:把源資料使用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;
immer結合setState使用
-
第一個參數就隐式傳遞給了代理對象,隻需要第二個函數參數即可去執行
-函數參數不能有傳回值
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;
優化immer,useState結合使用
變量如果是普通的數字,而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;
immer寫法對于數組,對象的操作很友好
不能傳回,寫上去感覺就像在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;
immer和redux結合使用
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)
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;