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使用,提高性能的主要内容,如果未能解决你的问题,请参考以下文章

setState详解与React性能优化

从 0 到 1 实现 React 系列 —— 4.setState优化和ref的实现

ReactReact全家桶 -setState-路由组件懒加载-Fragment-Context-组件优化-render props-错误边界-消息订阅发布机制-组件通信方式总结

ReactReact全家桶 -setState-路由组件懒加载-Fragment-Context-组件优化-render props-错误边界-消息订阅发布机制-组件通信方式总结

ReactReact全家桶 -setState-路由组件懒加载-Fragment-Context-组件优化-render props-错误边界-消息订阅发布机制-组件通信方式总结

11.React原理及优化