• React中Immutable的使用



    1. 介绍

    假设当前 redux 的大小为 1G,现在要修改 redux 树中的某个节点(节点的大小很小),我们就需要深复制整棵 redux 树,只为了修改很少的数据,这样对于性能的损耗是非常大的。于是我们使用 Immutable 来对这一现象进行优化,Immutable 只会深复制发生改变的节点及其祖先节点,然后修改后返回新数据。

    Immutable.js 出自 Facebook,是非常流行的不可变数据结构的实现之一。它实现了完全的持久化数据结构,使用结构共享。所有的更新操作都会返回新的值,但是在内部结构是共享的,来减少内存占用。

    • 持久化数据结构:这里说的持久化是用来描述一种数据结构,指一个数据,在被修改时,仍然能够保持修改前的状态,即不可变类型。
    • 结构共享:Immutable 使用先进的 tries (字典树)技术实现结构共享来解决性能问题,当我们对一个 Immutable 对象进行操作的时候, ImmutableJS 会只 clone 该节点以及它的祖先节点,其他保持不变,这样可以共享相同的部分,大大提高性能。
    • 惰性操作:创建的对象时其实代码块没有被执行,只是被声明了,代码在获取或修改的时候才会实际被执行

    Immutable 的安装:yarn add immutable

    2. 优缺点

    • 优点

      • 降低对象深复制带来的复杂度
      • 节省内存
      • 历史追溯性
    • 缺点

      • 需要重新学习api
      • 容易与原生对象混淆:由于api与原生不同,混用的话容易出错
      • 第3方组件库不支持,使用时,还需要转换

    3. 对象处理

    使用 Map 和 formJS 方法将 js 对象转化为 immutable 对象,并获取数据:

    import React, { Component } from 'react'
    // Map, List 是方法也是类型
    // Map方法,可以把json对象第1层转为immutable对象中的Map类型
    // List方法,可以把数组第1层转为 immutable对象中的List类型
    // fromJS方法,可以自动递归所以有对象或数组,自动转为对象的immutable类型
    import { Map, List, fromJS } from 'immutable'
    
    console.log("============ Map方法 ==============")
    const state = { id: 1, name: '张三' }
    
    const imState = Map(state)
    console.log(imState)
    // 获取数据 get / getIn  没有值就返回undefined
    console.log(imState.get('name'))
    console.log(imState.getIn(['name']))
    
    
    console.log("========== formJs方法 ============")
    // Map方法只转一层,这时候使用 fromJS 方法
    const state1 = { id: 1, name: { username: '李四' } }
    const imState1 = fromJS(state1)
    console.log(imState)
    console.log(imState1.get('name').get('username'))
    // getIn 独特写法
    console.log(imState1.getIn(['name', 'username']))
    
    class App extends Component {
      render() {
        return (
          <div>
            <h3>App组件之immutablejs学习</h3>
          </div>
        )
      }
    }
    
    export default App
    

    在这里插入图片描述

    修改数据:

    import React, { Component } from 'react'
    // Map, List 是方法也是类型
    // Map方法,可以把json对象第1层转为immutable对象中的Map类型
    // List方法,可以把数组第1层转为 immutable对象中的List类型
    // fromJS方法,可以自动递归所以有对象或数组,自动转为对象的immutable类型
    import { Map, List, fromJS } from 'immutable'
    
    // 修改数据  set/setIn update/updateIn  修改数据后会返回一个新的state数据
    // set 相关方法,不关心原数据,直接赋值
    // update 相关方法,在原数据基础上修改
    const state = { id: 1, name: { username: '李四', age: 10 } }
    const imState = fromJS(state)
    
    const newImState = imState.set('id', 3)
    // toJS 把immutable对象转为js对象
    // 这里能获取新旧数据,体现出 immutable 历史可追溯的优点
    console.log('newImState:',newImState.toJS(), imState.toJS())
    
    const newImState1 = imState.setIn(['name', 'age'], 20)
    console.log('newImState1:',newImState1.toJS())
    
    const newImState2 = imState.update('id', val => val + 1)
    console.log('newImState2:',newImState2.toJS())
    
    const newImState3 = imState.updateIn(['name', 'age'], val => val + 1)
    console.log('newImState3:',newImState3.toJS())
    
    class App extends Component {
      render() {
        return (
          <div>
            <h3>App组件之immutablejs学习</h3>
          </div>
        )
      }
    }
    
    export default App
    

    在这里插入图片描述

    删除数据:

    import React, { Component } from 'react'
    // Map, List 是方法也是类型
    // Map方法,可以把json对象第1层转为immutable对象中的Map类型
    // List方法,可以把数组第1层转为 immutable对象中的List类型
    // fromJS方法,可以自动递归所以有对象或数组,自动转为对象的immutable类型
    import { Map, List, fromJS } from 'immutable'
    
    // 删除 remove/removeIn/delete/deleteIn 别名
    const state = { id: 1, name: { username: '李四', age: 10 } }
    const imState = fromJS(state)
    const newImState = imState.remove('id')
    console.log(newImState.toJS())
    
    class App extends Component {
      render() {
        return (
          <div>
            <h3>App组件之immutablejs学习</h3>
          </div>
        )
      }
    }
    
    export default App
    

    在这里插入图片描述

    合并数据:

    import React, { Component } from 'react'
    // Map, List 是方法也是类型
    // Map方法,可以把json对象第1层转为immutable对象中的Map类型
    // List方法,可以把数组第1层转为 immutable对象中的List类型
    // fromJS方法,可以自动递归所以有对象或数组,自动转为对象的immutable类型
    import { Map, List, fromJS } from 'immutable'
    
    // 合并
    const id = fromJS({ id: 1 })
    const name = fromJS({ name: '张三' })
    const imState1 = name.merge(id)
    const imState2 = name.concat(id)
    console.log(imState1.toJS())
    console.log(imState2.toJS())
    
    class App extends Component {
      render() {
        return (
          <div>
            <h3>App组件之immutablejs学习</h3>
          </div>
        )
      }
    }
    
    export default App
    

    在这里插入图片描述

    4. 数组处理

    查看长度和获取数据:

    import React, { Component } from 'react'
    // Map, List 方法也是类似
    // Map方法,可以把json对象第1层转为immutable对象中的Map类型
    // List方法,可以把数组第1层转为 immutable对象中的List类型
    // fromJS方法,可以自动递归所以有对象可数组,自动转为对象的immutable类型
    import { Map, List, fromJS } from 'immutable'
    
    // ------------ 数组转为List
    // { name: '张三' } 转为了map
    const state = [1, 2, { name: '张三' }]
    const imState = fromJS(state)
    // 查看当前长度
    console.log(imState.size);
    // 获取 get/getIn
    console.log(imState.get(2).get('name'))
    console.log(imState.getIn([2, 'name']))
    
    class App extends Component {
      render() {
        return (
          <div>
            <h3>App组件之immutablejs学习</h3>
          </div>
        )
      }
    }
    
    export default App
    

    在这里插入图片描述

    修改数据:

    import React, { Component } from 'react'
    // Map, List 方法也是类似
    // Map方法,可以把json对象第1层转为immutable对象中的Map类型
    // List方法,可以把数组第1层转为 immutable对象中的List类型
    // fromJS方法,可以自动递归所以有对象可数组,自动转为对象的immutable类型
    import { Map, List, fromJS } from 'immutable'
    
    // 操作 push/pop/unshift/shift/splice/concat
    // set/setIn update/updateIn
    const state = [1, 2, { name: '张三', arr: [20] }]
    const imState = fromJS(state)
    
    // 把第0个元素修改为10
    const newImState1 = imState.set(0, 10)
    console.log(newImState1.toJS())
    // 把第2个元素中的arr中的第0个改为10
    const newImState2 = imState.setIn([2,'arr',0], 10)
    console.log(newImState2.toJS())
    // 
    const newImState3 = imState.update(0, val => val + 1)
    console.log(newImState3.toJS())
    
    const newImState = imState.updateIn([2, 'arr', 0], v => v + 1)
    console.log(newImState.toJS())
    
    class App extends Component {
      render() {
        return (
          <div>
            <h3>App组件之immutablejs学习</h3>
          </div>
        )
      }
    }
    
    export default App
    

    在这里插入图片描述

    删除元素:

    import React, { Component } from 'react'
    // Map, List 方法也是类似
    // Map方法,可以把json对象第1层转为immutable对象中的Map类型
    // List方法,可以把数组第1层转为 immutable对象中的List类型
    // fromJS方法,可以自动递归所以有对象可数组,自动转为对象的immutable类型
    import { Map, List, fromJS } from 'immutable'
    
    // 删除
    const imState = fromJS([1, 2, { name: '张三', arr: [20] }])
    const newImState = imState.remove(1)
    console.log(newImState.toJS())
    
    class App extends Component {
      render() {
        return (
          <div>
            <h3>App组件之immutablejs学习</h3>
          </div>
        )
      }
    }
    
    export default App
    

    在这里插入图片描述

    5. 优化组件渲染

    immutable 中有一个 is 方法,可以比较两个immutable对象值是否一致,如果一致则返回true 否则为false。

    import React, { Component } from 'react'
    import _ from 'lodash'
    // is 比较两个immutable对象值是否一致,如果一致则返回true 否则为false
    import { Map, List, fromJS, is } from 'immutable'
    
    // 比较两个对象的值是否一样
    // const obj1 = { id: 1 }
    // const obj2 = { id: 1 }
    
    // 我们知道这种情况下,输出一定为 false,如何只比较值该怎么做?
    // console.log(obj1 == obj2)
    // console.log(obj1 === obj2)
    
    // 方案1:值它是一样的  使用此方法,它会进行值的比对,如果对象它的层级深,比对的速度就慢
    // console.log(_.isEqual(obj1, obj2))
    
    const obj1 = fromJS({ id: 1 })
    const obj2 = fromJS({ id: 1 })
    
    // false
    console.log(obj1 == obj2)
    // true
    console.log(is(obj1, obj2))
    
    class App extends Component {
      render() {
        return (
          <div>
            <h3>App组件之immutablejs学习</h3>
          </div>
        )
      }
    }
    
    export default App
    

    利用这个方法,我们可以优化组件渲染,例如下面这种情况:

    App.jsx

    import React, { Component } from 'react'
    import Child from './components/Child'
    
    class App extends Component {
      state = {
        user: { num: 100 }
      }
      render() {
        return (
          <div>
            <h3>App组件之immutablejs学习 -- {this.state.user.num}</h3>
            <hr />
            <Child user={this.state.user} />
            <hr />
            {/* 此时子组件不会渲染 */}
            {/*  */}
            {/* 此时子组件会重新渲染 */}
            <button onClick={() => this.setState({ user: { num: Date.now() } })}>+++++</button>
          </div>
        )
      }
    }
    
    export default App
    

    子组件:

    import React, { Component } from 'react'
    import { fromJS, is } from 'immutable'
    
    class Child extends Component {
      shouldComponentUpdate(nextProps, nextState) {
        // 如果最新的props对象和父组件传过来的props对象不一致,则更新子组件,否则子组件不更新
        // 这样可以优化性能
        return !is(fromJS(nextProps), fromJS(this.props))
      }
    
      render() {
        console.log('child -- render')
        return (
          <div>
            <h3>child组件</h3>
          </div>
        )
      }
    }
    
    export default Child
    

    在这里插入图片描述

    6. immutable和redux集合使用

    安装:

    redux 中利用 combineReducers 来合并 reducer 并初始化 state ,redux 自带的 combineReducers 只支持 state 是原生 js 形式的,所以需要使用 redux-immutable 提供的 combineReducers 来替换原来的方法。

    yarn add redux-immutable

    使用:

    它的合并是支持immutable对象合并:

    import { combineReducers } from 'redux-immutable'
    

    把所有的reducer数据转换为immutable对象:

    import {fromJS} from 'immutable'
    const defaultState = fromJS({})
    
  • 相关阅读:
    100097. 合法分组的最少组数
    SiC外延片测试方案
    SpringBoot 3.2.5 + ElasticSearch 8.12.0 - SpringData 开发指南
    ​GOPS演讲 | 如何构建现代运营与支持体系,实现团队的高效协同
    ICP问题 SVD方法推导(Markdown版)
    菲律宾外汇储备降至两年来的最低水平
    qemu侧 网络包发送调试记录(二)
    企业帮助中心如何在线搭建,还能多场景使用呢?
    【java学习】面向对象特征之一:封装和隐藏(23)
    IO作业:使用函数 使用线程实现,实现能够随时收发,即AB可以 随时 互相收发消息:提示 用多线程 或者多进程
  • 原文地址:https://blog.csdn.net/weixin_45605541/article/details/127097299