天天看點

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)      
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;      

繼續閱讀