immer的使用——优化setState——优化useState——优化redux使用,提高性能
Posted 勇敢*牛牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了immer的使用——优化setState——优化useState——优化redux使用,提高性能相关的知识,希望对你有一定的参考价值。
它和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)
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;
以上是关于immer的使用——优化setState——优化useState——优化redux使用,提高性能的主要内容,如果未能解决你的问题,请参考以下文章
从 0 到 1 实现 React 系列 —— 4.setState优化和ref的实现
ReactReact全家桶 -setState-路由组件懒加载-Fragment-Context-组件优化-render props-错误边界-消息订阅发布机制-组件通信方式总结
ReactReact全家桶 -setState-路由组件懒加载-Fragment-Context-组件优化-render props-错误边界-消息订阅发布机制-组件通信方式总结
ReactReact全家桶 -setState-路由组件懒加载-Fragment-Context-组件优化-render props-错误边界-消息订阅发布机制-组件通信方式总结