当前位置: 首页 > 工具软件 > immer > 使用案例 >

immer的使用——优化setState——优化useState——优化redux使用,提高性能

邢财
2023-12-01

它和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;

 类似资料: