更好的阅读体验

更好的阅度体验

Immutable.js

Immutable的优势

1. 保证不可变(每次通过Immutable.js操作的对象都会返回一个新的对象)
2. 丰富的API
3. 性能好 (通过字典树对数据结构的共享)

**Immutable的问题**

1. 与原生JS交互不友好 (通过Immutable生成的对象在操作上与原生JS不同,如访问属性,myObj.prop1.prop2.prop3 => myImmutableMap.getIn([‘prop1’, ‘prop2’, ‘prop3’])。另外其他的第三方库可能需要的是一个普通的对象)
2. Immutable的依赖性极强 (一旦在代码中引入使用,很容易传播整个代码库,并且很难在将来的版本中移除)
3. 不能使用解构和对象运算符 (相对来说,代码的可读性差)
4. 不适合经常修改的简单对象 (Immutable的性能比原生慢,如果对象简单,并且经常修改,不适合用)
5. 难以调试 (可以采用 Immutable.js Object Formatter扩展程序协助)
6. 破坏JS原生对象的引用,造成性能低下 (toJs每次都会返回一个新对象)

原生Js遇到的问题

原生Js遇到的问题

// 场景一
var obj = {a:1, b:{c:2}};
func(obj);
console.log(obj) //输出什么?? // 场景二
var obj = ={a:1};
var obj2 = obj;
obj2.a = 2;
console.log(obj.a); // 2
console.log(obj2.a); // 2 代码来源:https://juejin.im/post/5948985ea0bb9f006bed7472
// ajax1
this.props.a = {
data: 1,
}
// ajax2
nextProps.a = {
data: 1,
}
//shouldComponentUpdate()
shallowEqual(this.props, nextProps) // false
// 数据相同但是因为引用不同而造成不必要的re-rederning
由于Js中的对象是引用类型的,所以很多时候我们并不知道我们的对象在哪里被操作了什么,而在Redux中,因为Reducer是一个纯函数,每次返回的都是一个新的对象(重新生成对象占用时间及内存),再加上我们使用了connect这个高阶组件,官方文档中虽然说react-redux做了一些性能优化,但终究起来,react-redux只是对传入的参数进行了一个浅比较来进行re-redering(为什么不能在mapStateToProps中使用toJs的原因)。再进一步,假如我们的state中的属性嵌套了好几层(随着业务的发展),对于原来想要的数据追踪等都变得极为困难,更为重要的是,在这种情况下,我们一些没有必要的组件很可能重复渲染了多次。

总结起来就是以下几点(问题虽少,但都是比较严重的):

1. 无法追踪Js对象
2. 项目复杂时,reducer生成新对象性能低
3. 只做浅比较,有可能会造成re-redering不符合预期(多次渲染或不更新)

为什么不使用深比较

或许有人会疑惑,为什么不使用深比较来解决re-redering的问题,答案很简单,因为消耗非常巨大~
想象一下,如果你的参数复杂且巨大, 对每一个进行比较是多么消耗时间的一件事~

使用Immutable解决问题

项目复杂后, 追踪困难

使用Immutable之后,这个问题自然而然就解决了。所谓的追踪困难,无非就是因为对象是mutable的,我们无法确定它到底何时何处被改变,而Immutable每次都会保留原来的对象,重新生成一个对象,(与redux的纯函数概念一样)。但也要注意写代码时的习惯:

// javascript
const obj = { a: 1 }
function (obj) {
obj.b = 2
...
} // Immutable
const obj = Map({ a : 1 })
function (obj) {
const obj2 = obj.set({ 'b', 2 })
}

reducer生成新对象性能差

当项目变得复杂时,每一次action对于生成的新state都会消耗一定的性能,而Immutable.js在这方面的优化就很好。或许你会疑惑为什么生成对象还能优化?请往下看~

在前面就讲到,Immutable是通过字典树来做结构共享的



(图片来自网络)

这张图的意思就是

immutable使用先进的tries(字典树)技术实现结构共享来解决性能问题,当我们对一个Immutable对象进行操作的时候,ImmutableJS会只clone该节点以及它的祖先节点,其他保持不变,这样可以共享相同的部分,大大提高性能。

re-rendering不符合预期

其实解决这个问题是我们用Immutable的主要目的,先从浅比较说起

浅比较引起的问题在这之前已经讲过,事实上,即使Immutable之后,connect所做的依然是浅比较,但因为Immutable每次生成的对象引用都不同,哪怕是修改的是很深层的东西,最后比较的结果也是不同的,所以在这里解决了第一个问题,re-rendering可能不会出现。

但是, 我们还有第二个问题, 没必要的re-rendering,想要解决这个问题,则需要我们再封装一个高阶组件,在这之前需要了解下Immutable的 is API

// is()   判断两个immutable对象是否相等
immutable.is(imA, imB);

这个API有什么不同, 这个API比较的是值,而不是引用,So: 只要两个值是一样的,那么结果就是true

const a = Immutable.fromJS({
a: {
data: 1,
},
b: {
newData: {
data: 1
}
}
})
const target1 = a.get('a')
const target2 = a.getIn(['b', 'newData'])
console.log(Immutable.is(target1, target2)) //is比较的依据就是每个值的hashcode
// 这个hashcode就相当于每个值的一个ID,不同的值肯定有不同的ID,相同的ID对应着的就是相同的值。

也就是说,对于下面的这种情况, 我们可以不用渲染

// ajax1
this.props.a = {
data: 1,
}
// ajax2
nextProps.a = {
data: 1,
}
//shouldComponentUpdate()
Immutable.is(this.props, nextProps) // true

最后, 我们需要封装一个高阶组件来帮助我们统一处理是否需要re-rendering的情况

//baseComponent.js   component的基类方法

import React from 'react';
import {is} from 'immutable'; class BaseComponent extends React.Component {
constructor(props, context, updater) {
super(props, context, updater);
} shouldComponentUpdate(nextProps, nextState) {
const thisProps = this.props || {};
const thisState = this.state || {};
nextState = nextState || {};
nextProps = nextProps || {}; if (Object.keys(thisProps).length !== Object.keys(nextProps).length ||
Object.keys(thisState).length !== Object.keys(nextState).length) {
return true;
} for (const key in nextProps) {
if (!is(thisProps[key], nextProps[key])) {
return true;
}
} for (const key in nextState) {
if (!is(thisState[key], nextState[key])) {
return true;
}
}
return false;
}
} export default BaseComponent; 代码来源链接:https://juejin.im/post/5948985ea0bb9f006bed7472

使用Immutable需要注意的点

使用Immutable需要注意的点

1. 不要混合普通的JS对象和Immutable对象 (不要把Imuutable对象作为Js对象的属性,或者反过来)
2. 对整颗Reudx的state树作为Immutable对象
3. 除了展示组件以外,其他地方都应该使用Immutable对象 (提高效率,而展示组件是纯组件,不应该使用)
4. 少用toJS方法 (一个是因为否定了Immutable,另外则是操作非常昂贵)
5. 你的Selector应该永远返回Immutable对象 (即mapStateToProps,因为react-redux中是通过浅比较来决定是否re-redering,而使用toJs的话,每次都会返回一个新对象,即引用不同)

通过高阶组件,将Immutable对象转为普通对象传给展示组件

1. 高阶组件返回一个新的组件,该组件接受Immutable参数,并在内部转为普通的JS对象
2. 转为普通对象后, 新组件返回一个入参为普通对象的展示组件
import React from 'react'
import { Iterable } from 'immutable' export const toJS = WrappedComponent => wrappedComponentProps => {
const KEY = 0
const VALUE = 1 const propsJS = Object.entries(wrappedComponentProps).reduce(
(newProps, wrappedComponentProp) => {
newProps[wrappedComponentProp[KEY]] = Iterable.isIterable(
wrappedComponentProp[VALUE]
)
? wrappedComponentProp[VALUE].toJS()
: wrappedComponentProp[VALUE]
return newProps
},
{}
) return <WrappedComponent {...propsJS} />
}
import { connect } from 'react-redux'

import { toJS } from './to-js'
import DumbComponent from './dumb.component' const mapStateToProps = state => {
return {
// obj is an Immutable object in Smart Component, but it’s converted to a plain
// JavaScript object by toJS, and so passed to DumbComponent as a pure JavaScript
// object. Because it’s still an Immutable.JS object here in mapStateToProps, though,
// there is no issue with errant re-renderings.
obj: getImmutableObjectFromStateTree(state)
}
}
export default connect(mapStateToProps)(toJS(DumbComponent))

参考

Immutable.js 以及在 react+redux 项目中的实践
Using Immutable.JS with Redux
不变应万变-Immutable优化React
React-Redux分析

Redux进阶(Immutable.js)的更多相关文章

  1. immutable.js 在React、Redux中的实践以及常用API简介

    immutable.js 在React.Redux中的实践以及常用API简介 学习下 这个immutable Data 是什么鬼,有什么优点,好处等等 mark :  https://yq.aliyu ...

  2. Immutable.js 以及在 react+redux 项目中的实践

    来自一位美团大牛的分享,相信可以帮助到你. 原文链接:https://juejin.im/post/5948985ea0bb9f006bed7472?utm_source=tuicool&ut ...

  3. 大话immutable.js

    为啥要用immutable.js呢.毫不夸张的说.有了immutable.js(当然也有其他实现库)..才能将react的性能发挥到极致!要是各位看官用过一段时间的react,而没有用immutabl ...

  4. React+Immutable.js的心路历程

    这段时间做的项目开发中用的是React+Redux+ImmutableJs+Es6开发,总结了immutable.js的相关使用姿势: Immutable Data 顾名思义是指一旦被创造后,就不可以 ...

  5. immutable.js 更新数组(mergeDeepWith)

    使用情境: 技术栈为:react + redux + antd (reducer中处理数据使用了immutable.js). 问题:如下图,做一个搜索功能,form表单每改变一次,都会调用一个upda ...

  6. Redux进阶(像VUEX一样使用Redux)

    更好的阅度体验 前言 redux的问题 方案目标 如何实现 思考 前言 Redux是一个非常实用的状态管理库,对于大多数使用React库的开发者来说,Redux都是会接触到的.在使用Redux享受其带 ...

  7. 深度浅出immutable.js

    这篇文章将讲述immutable.js的基本语法和用法. 1.fromJs()  Deeply converts plain JS objects and arrays to Immutable Ma ...

  8. Immutable.js – JavaScript 不可变数据集合

    不可变数据是指一旦创建就不能被修改的数据,使得应用开发更简单,允许使用函数式编程技术,比如惰性评估.Immutable JS 提供一个惰性 Sequence,允许高效的队列方法链,类似 map 和 f ...

  9. Immutable.js尝试(node.js勿入)

    最近做一些复杂html常常需要在页面做一些数据处理,常常在想如果 js有list 这种数据结构多少,今天逛github时 发现有Immutable.js 这个项目https://github.com/ ...

随机推荐

  1. /usr/lib/python2.7/site-packages/requests/__init__.py:80: RequestsDependencyWarning: urllib3 (1.22) or chardet (2.2.1) doesn't match a supported version! RequestsDependencyWarning)

    [root@iZwz9bhan5nqzh979qokrkZ ~]# ansible all -m ping /usr/lib/python2.7/site-packages/requests/__in ...

  2. 获取jwt(json web token)中存储的用户信息

    一个JWT实际上就是一个字符串,它由三部分组成,头部(header).载荷(Payload)与签名. Payload payload中可以保存用户的信息. var claims = new Claim ...

  3. 4.28Linux(6)

    2019-4-28 21:27:41 明天回家.回家继续学Linux还好有个服务器!!!感觉有个属于自己的服务器感觉好爽啊!! 越努力越幸运!永远不要高估自己!!! Nginx安装 服务器的请求原理 ...

  4. 4.23 Linux(3)

    2019-4-23 19:03:53 买的服务器第三天感觉超爽!! 发现学习Linux超爽,有种操作的快感!!!!!是Windows比不了的!! 阿里巴巴镜像源 : https://opsx.alib ...

  5. 排查MongoDB CPU使用率高的问题

    1.公司业务调整,把一部分数据由Redis转至MongoDB,业务在测试环境正常,生产环境上线后发现压力一上来MongoDB的服务直接把CPU占满了,和开发的同学分析了一下也参考了一下百度上类似的问题 ...

  6. DataRow[]

    datarow[]是datatable 的行数组集合,但是呢好像是不能直接初始化,只能是datarow[] rows = dt.select(condition);这样子.(也可能我才疏学浅没找到吧) ...

  7. Android 实现卡片翻转的动画(翻牌动画)

    Android 实现卡片翻转的动画(翻牌动画) 需求描述 点击卡片,卡片翻转过来显示内容. 点击左边的卡片,将卡片翻转显示右边的图片结果. 功能实现 因为要翻转所以使用动画来完成翻转的动画.动画分为两 ...

  8. Node.js(day3)

    一.模块系统 1.什么是模块 Node.js中常用的核心模块有: http模块 fs文件系统模块 url模块 path模块 os系统模块 在使用Node.js中我们发现每个js之间是没有联系的,都是单 ...

  9. [Swift]LeetCode62. 不同路径 | Unique Paths

    A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The ...

  10. [Swift]LeetCode95. 不同的二叉搜索树 II | Unique Binary Search Trees II

    Given an integer n, generate all structurally unique BST's (binary search trees) that store values 1 ...