New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Immutable 详解及 React 中实践 #3

Open
camsong opened this Issue Oct 26, 2015 · 50 comments

Comments

Projects
None yet
@camsong
Owner

camsong commented Oct 26, 2015

Immutable data

Shared mutable state is the root of all evil(共享的可变状态是万恶之源)

-- Pete Hunt

有人说 Immutable 可以给 React 应用带来数十倍的提升,也有人说 Immutable 的引入是近期 JavaScript 中伟大的发明,因为同期 React 太火,它的光芒被掩盖了。这些至少说明 Immutable 是很有价值的,下面我们来一探究竟。

JavaScript 中的对象一般是可变的(Mutable),因为使用了引用赋值,新的对象简单的引用了原始对象,改变新的对象将影响到原始对象。如 foo={a: 1}; bar=foo; bar.a=2 你会发现此时 foo.a 也被改成了 2。虽然这样做可以节约内存,但当应用复杂后,这就造成了非常大的隐患,Mutable 带来的优点变得得不偿失。为了解决这个问题,一般的做法是使用 shallowCopy(浅拷贝)或 deepCopy(深拷贝)来避免被修改,但这样做造成了 CPU 和内存的浪费。

Immutable 可以很好地解决这些问题。

什么是 Immutable Data

Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。Immutable 实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。请看下面动画:

Immutable 原理动画

目前流行的 Immutable 库有两个:

immutable.js

Facebook 工程师 Lee Byron 花费 3 年时间打造,与 React 同期出现,但没有被默认放到 React 工具集里(React 提供了简化的 Helper)。它内部实现了一套完整的 Persistent Data Structure,还有很多易用的数据类型。像 CollectionListMapSetRecordSeq。有非常全面的mapfiltergroupByreduce``find函数式操作方法。同时 API 也尽量与 Object 或 Array 类似。

其中有 3 种最重要的数据结构说明一下:(Java 程序员应该最熟悉了)

  • Map:键值对集合,对应于 Object,ES6 也有专门的 Map 对象
  • List:有序可重复的列表,对应于 Array
  • Set:无序且不可重复的列表

seamless-immutable

与 Immutable.js 学院派的风格不同,seamless-immutable 并没有实现完整的 Persistent Data Structure,而是使用 Object.defineProperty(因此只能在 IE9 及以上使用)扩展了 JavaScript 的 Array 和 Object 对象来实现,只支持 Array 和 Object 两种数据类型,API 基于与 Array 和 Object 操持不变。代码库非常小,压缩后下载只有 2K。而 Immutable.js 压缩后下载有 16K。

下面上代码来感受一下两者的不同:

// 原来的写法
let foo = {a: {b: 1}};
let bar = foo;
bar.a.b = 2;
console.log(foo.a.b);  // 打印 2
console.log(foo === bar);  //  打印 true

// 使用 immutable.js 后
import Immutable from 'immutable';
foo = Immutable.fromJS({a: {b: 1}});
bar = foo.setIn(['a', 'b'], 2);   // 使用 setIn 赋值
console.log(foo.getIn(['a', 'b']));  // 使用 getIn 取值,打印 1
console.log(foo === bar);  //  打印 false

// 使用  seamless-immutable.js 后
import SImmutable from 'seamless-immutable';
foo = SImmutable({a: {b: 1}})
bar = foo.merge({a: { b: 2}})   // 使用 merge 赋值
console.log(foo.a.b);  // 像原生 Object 一样取值,打印 1
console.log(foo === bar);  //  打印 false

Immutable 优点

1. Immutable 降低了 Mutable 带来的复杂度

可变(Mutable)数据耦合了 Time 和 Value 的概念,造成了数据很难被回溯。

比如下面一段代码:

function touchAndLog(touchFn) {
  let data = { key: 'value' };
  touchFn(data);
  console.log(data.key); // 猜猜会打印什么?
}

在不查看 touchFn 的代码的情况下,因为不确定它对 data 做了什么,你是不可能知道会打印什么(这不是废话吗)。但如果 data 是 Immutable 的呢,你可以很肯定的知道打印的是 value

2. 节省内存

Immutable.js 使用了 Structure Sharing 会尽量复用内存,甚至以前使用的对象也可以再次被复用。没有被引用的对象会被垃圾回收。

import { Map} from 'immutable';
let a = Map({
  select: 'users',
  filter: Map({ name: 'Cam' })
})
let b = a.set('select', 'people');

a === b; // false
a.get('filter') === b.get('filter'); // true

上面 a 和 b 共享了没有变化的 filter 节点。

3. Undo/Redo,Copy/Paste,甚至时间旅行这些功能做起来小菜一碟

因为每次数据都是不一样的,只要把这些数据放到一个数组里储存起来,想回退到哪里就拿出对应数据即可,很容易开发出撤销重做这种功能。

后面我会提供 Flux 做 Undo 的示例。

4. 并发安全

传统的并发非常难做,因为要处理各种数据不一致问题,因此『聪明人』发明了各种锁来解决。但使用了 Immutable 之后,数据天生是不可变的,并发锁就不需要了

然而现在并没什么卵用,因为 JavaScript 还是单线程运行的啊。但未来可能会加入,提前解决未来的问题不也挺好吗?

5. 拥抱函数式编程

Immutable 本身就是函数式编程中的概念,纯函数式编程比面向对象更适用于前端开发。因为只要输入一致,输出必然一致,这样开发的组件更易于调试和组装。

像 ClojureScript,Elm 等函数式编程语言中的数据类型天生都是 Immutable 的,这也是为什么 ClojureScript 基于 React 的框架 --- Om 性能比 React 还要好的原因。

Immutable 缺点

1. 需要学习新的 API

No Comments

2. 增加了资源文件大小

No Comments

3. 容易与原生对象混淆

这点是我们使用 Immutable.js 过程中遇到最大的问题。写代码要做思维上的转变。

虽然 Immutable.js 尽量尝试把 API 设计的原生对象类似,有的时候还是很难区别到底是 Immutable 对象还是原生对象,容易混淆操作。

Immutable 中的 Map 和 List 虽对应原生 Object 和 Array,但操作非常不同,比如你要用 map.get('key') 而不是 map.keyarray.get(0) 而不是 array[0]。另外 Immutable 每次修改都会返回新对象,也很容易忘记赋值。

当使用外部库的时候,一般需要使用原生对象,也很容易忘记转换。

下面给出一些办法来避免类似问题发生:

  1. 使用 Flow 或 TypeScript 这类有静态类型检查的工具
  2. 约定变量命名规则:如所有 Immutable 类型对象以 $$ 开头。
  3. 使用 Immutable.fromJS 而不是 Immutable.MapImmutable.List 来创建对象,这样可以避免 Immutable 和原生对象间的混用。

更多认识

Immutable.is

两个 immutable 对象可以使用 === 来比较,这样是直接比较内存地址,性能最好。但即使两个对象的值是一样的,也会返回 false

let map1 = Immutable.Map({a:1, b:1, c:1});
let map2 = Immutable.Map({a:1, b:1, c:1});
map1 === map2;             // false

为了直接比较对象的值,immutable.js 提供了 Immutable.is 来做『值比较』,结果如下:

Immutable.is(map1, map2);  // true

Immutable.is 比较的是两个对象的 hashCodevalueOf(对于 JavaScript 对象)。由于 immutable 内部使用了 Trie 数据结构来存储,只要两个对象的 hashCode 相等,值就是一样的。这样的算法避免了深度遍历比较,性能非常好。

后面会使用 Immutable.is 来减少 React 重复渲染,提高性能。

另外,还有 moricortex 等,因为类似就不再介绍。

与 Object.freeze、const 区别

Object.freeze 和 ES6 中新加入的 const 都可以达到防止对象被篡改的功能,但它们是 shallowCopy 的。对象层级一深就要特殊处理了。

Cursor 的概念

这个 Cursor 和数据库中的游标是完全不同的概念。

由于 Immutable 数据一般嵌套非常深,为了便于访问深层数据,Cursor 提供了可以直接访问这个深层数据的引用。

import Immutable from 'immutable';
import Cursor from 'immutable/contrib/cursor';

let data = Immutable.fromJS({ a: { b: { c: 1 } } });
// 让 cursor 指向 { c: 1 }
let cursor = Cursor.from(data, ['a', 'b'], newData => {
  // 当 cursor 或其子 cursor 执行 update 时调用
  console.log(newData);
});

cursor.get('c'); // 1
cursor = cursor.update('c', x => x + 1);
cursor.get('c'); // 2

实践

与 React 搭配使用,Pure Render

熟悉 React 的都知道,React 做性能优化时有一个避免重复渲染的大招,就是使用 shouldComponentUpdate(),但它默认返回 true,即始终会执行 render() 方法,然后做 Virtual DOM 比较,并得出是否需要做真实 DOM 更新,这里往往会带来很多无必要的渲染并成为性能瓶颈。

当然我们也可以在 shouldComponentUpdate() 中使用使用 deepCopy 和 deepCompare 来避免无必要的 render(),但 deepCopy 和 deepCompare 一般都是非常耗性能的

Immutable 则提供了简洁高效的判断数据是否变化的方法,只需 ===is 比较就能知道是否需要执行 render(),而这个操作几乎 0 成本,所以可以极大提高性能。修改后的 shouldComponentUpdate 是这样的:

注意:React 中规定 stateprops 只能是一个普通对象,所以比较时要比较对象的 key,谢谢 @chenmnkken 指正。

import { is } from 'immutable';

shouldComponentUpdate: (nextProps = {}, nextState = {}) => {
  const thisProps = this.props || {}, thisState = this.state || {};

  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 (thisState[key] !== nextState[key] && !is(thisState[key], nextState[key])) {
      return true;
    }
  }
  return false;
}

使用 Immutable 后,如下图,当红色节点的 state 变化后,不会再渲染树中的所有节点,而是只渲染图中绿色的部分:

react reconciliation

你也可以借助 React.addons.PureRenderMixin 或支持 class 语法的 [pure-render-decorator](felixgirault/pure-render-decorator · GitHub) 来实现。

setState 的一个技巧

React 建议把 this.state 当作 Immutable 的,因此修改前需要做一个 deepCopy,显得麻烦:

import '_' from 'lodash';

const Component = React.createClass({
  getInitialState() {
    return {
      data: { times: 0 }
    }
  },
  handleAdd() {
    let data = _.cloneDeep(this.state.data);
    data.times = data.times + 1;
    this.setState({ data: data });
    // 如果上面不做 cloneDeep,下面打印的结果会是已经加 1 后的值。
    console.log(this.state.data.times);
  }
}

使用 Immutable 后:

  getInitialState() {
    return {
      data: Map({ times: 0 })
    }
  },
  handleAdd() {
    this.setState({ data: this.state.data.update('times', v => v + 1) });
    // 这时的 times 并不会改变
    console.log(this.state.data.get('times'));
  }

上面的 handleAdd 可以简写成:

  handleAdd() {
    this.setState(({data}) => ({
      data: data.update('times', v => v + 1) })
    });
  }

与 Flux 搭配使用

由于 Flux 并没有限定 Store 中数据的类型,使用 Immutable 非常简单。

现在是实现一个类似带有添加和撤销功能的 Store:

import { Map, OrderedMap } from 'immutable';
let todos = OrderedMap();
let history = [];  // 普通数组,存放每次操作后产生的数据

let TodoStore = createStore({
  getAll() { return todos; }
});

Dispatcher.register(action => {
  if (action.actionType === 'create') {
    let id = createGUID();
    history.push(todos);  // 记录当前操作前的数据,便于撤销
    todos = todos.set(id, Map({
      id: id,
      complete: false,
      text: action.text.trim()
    }));
    TodoStore.emitChange();
  } else if (action.actionType === 'undo') {
    // 这里是撤销功能实现,
    // 只需从 history 数组中取前一次 todos 即可
    if (history.length > 0) {
      todos = history.pop();
    }
    TodoStore.emitChange();
  }
});

与 Redux 搭配使用

Redux 是目前流行的 Flux 衍生库。它简化了 Flux 中多个 Store 的概念,只有一个 Store,数据操作通过 Reducer 中实现;同时它提供更简洁和清晰的单向数据流(View -> Action -> Middleware -> Reducer),也更易于开发同构应用。目前已经在我们项目中大规模使用。

由于 Redux 中内置的 combineReducers 和 reducer 中的 initialState 都为原生的 Object 对象,所以不能和 Immutable 原生搭配使用。

幸运的是,Redux 并不排斥使用 Immutable,可以自己重写 combineReducers 或使用 redux-immutablejs 来提供支持。

上面我们提到 Cursor 可以方便检索和 update 层级比较深的数据,但因为 Redux 中已经有了 select 来做检索,Action 来更新数据,因此 Cursor 在这里就没有用武之地了。

总结

Immutable 可以给应用带来极大的性能提升,但是否使用还要看项目情况。由于侵入性较强,新项目引入比较容易,老项目迁移需要评估迁移。对于一些提供给外部使用的公共组件,最好不要把 Immutable 对象直接暴露在对外接口中。

如果 JS 原生 Immutable 类型会不会太美,被称为 React API 终结者的 Sebastian Markbåge 有一个这样的提案,能否通过现在还不确定。不过可以肯定的是 Immutable 会被越来越多的项目使用。

资源

如果你觉得本文对你有帮助,请点击右上方的 Star 鼓励一下,或者点击 Watch 订阅

@camsong camsong changed the title from Immutable 详解及 React 中使用 to Immutable 详解及 React 中实践 Oct 26, 2015

@AdrianHwang

This comment has been minimized.

Show comment
Hide comment
@AdrianHwang

AdrianHwang Oct 27, 2015

干货, 我拿走啦.

干货, 我拿走啦.

@hkongm

This comment has been minimized.

Show comment
Hide comment
@hkongm

hkongm Nov 10, 2015

好文,看到的文章中对Immutable解释最清晰的一个

hkongm commented Nov 10, 2015

好文,看到的文章中对Immutable解释最清晰的一个

@white87332

This comment has been minimized.

Show comment
Hide comment
@white87332

white87332 Nov 13, 2015

感謝好文, 讓我對Immutable又了解不少

感謝好文, 讓我對Immutable又了解不少

@Cuiyansong

This comment has been minimized.

Show comment
Hide comment
@Cuiyansong

Cuiyansong Nov 19, 2015

感谢好文 👍

感谢好文 👍

@chenmnkken

This comment has been minimized.

Show comment
Hide comment
@chenmnkken

chenmnkken Dec 20, 2015

import { is } from 'immutable';
shouldComponentUpdate: (nextProps, nextState) => {
  return !(this.props === nextProps || is(this.props, nextProps)) ||
         !(this.state === nextState || is(this.state, nextState));
}

这段代码好像有问题吧,由于 React 规定 state 只能是一个纯粹的对象,那么此时对比的就不是 immutable 对象,所以 shouldComponentUpdate 返回的结果永远是 true。Immutable 的 wiki 中有说明 https://github.com/facebook/immutable-js/wiki/Immutable-as-React-state

Note that state must be a plain JS object, and not an Immutable collection, because React's setState API expects an object literal and will merge it (Object.assign) with the previous state.

import { is } from 'immutable';
shouldComponentUpdate: (nextProps, nextState) => {
  return !(this.props === nextProps || is(this.props, nextProps)) ||
         !(this.state === nextState || is(this.state, nextState));
}

这段代码好像有问题吧,由于 React 规定 state 只能是一个纯粹的对象,那么此时对比的就不是 immutable 对象,所以 shouldComponentUpdate 返回的结果永远是 true。Immutable 的 wiki 中有说明 https://github.com/facebook/immutable-js/wiki/Immutable-as-React-state

Note that state must be a plain JS object, and not an Immutable collection, because React's setState API expects an object literal and will merge it (Object.assign) with the previous state.

@camsong

This comment has been minimized.

Show comment
Hide comment
@camsong

camsong Dec 20, 2015

Owner

@chenmnkken 谢谢指正,实际项目中使用了 react-immutable-render-mixin。这里写法确实有问题,已更正

Owner

camsong commented Dec 20, 2015

@chenmnkken 谢谢指正,实际项目中使用了 react-immutable-render-mixin。这里写法确实有问题,已更正

@yutingzhao1991

This comment has been minimized.

Show comment
Hide comment
@yutingzhao1991

yutingzhao1991 Jan 15, 2016

immutable还有一个问题就是写get太麻烦,其实在react中只有get没有set(对props来说),我再像能否在处理store(用了redux)的时候用immutable,但是当通过props传递给组件的时候改为普通的js对象。但是immutable的toJS其实是返回了一个复制后的对象,这样又失去了immutable优化性能的意义。

有什么好的解决方案吗?主要是太不适应一大堆get set了,而且经常会有混用的情况,很不爽。

immutable还有一个问题就是写get太麻烦,其实在react中只有get没有set(对props来说),我再像能否在处理store(用了redux)的时候用immutable,但是当通过props传递给组件的时候改为普通的js对象。但是immutable的toJS其实是返回了一个复制后的对象,这样又失去了immutable优化性能的意义。

有什么好的解决方案吗?主要是太不适应一大堆get set了,而且经常会有混用的情况,很不爽。

@camsong

This comment has been minimized.

Show comment
Hide comment
@camsong

camsong Jan 15, 2016

Owner

@yutingzhao1991 这个看个人喜好吧。immutableJS get 语法是这样的,没办法改。或者使用 seamless-immutable

因为默认下原生的 get 太方便了,再怎么设计API也很难超越。如果处理多层级可能为空的数据时,immutableJS 不需要做非空判断,这是优点。

foo = (((obj || []).level1 || {}).level2 || {}).level3
bar = obj.getIn(['level1', 'level2', 'level3']);
Owner

camsong commented Jan 15, 2016

@yutingzhao1991 这个看个人喜好吧。immutableJS get 语法是这样的,没办法改。或者使用 seamless-immutable

因为默认下原生的 get 太方便了,再怎么设计API也很难超越。如果处理多层级可能为空的数据时,immutableJS 不需要做非空判断,这是优点。

foo = (((obj || []).level1 || {}).level2 || {}).level3
bar = obj.getIn(['level1', 'level2', 'level3']);
@yutingzhao1991

This comment has been minimized.

Show comment
Hide comment
@yutingzhao1991

yutingzhao1991 Jan 15, 2016

@camsong 决定用 react-addons-update ,简单有效,只要确保所有修改的地方都调用这个update就好了,get还是用原生。

@camsong 决定用 react-addons-update ,简单有效,只要确保所有修改的地方都调用这个update就好了,get还是用原生。

@simongfxu simongfxu referenced this issue Feb 4, 2016

Open

Better React #28

@hacke2

This comment has been minimized.

Show comment
Hide comment
@hacke2

hacke2 Jun 7, 2016

我这边是展示的时候吧im对象转为原生,不知道这样有没有问题,,,:

export default connect(state => ({
    state: state.editor.toJSON()
}), (dispatch) => ({
    actions: bindActionCreators(editorAction, dispatch)
}))(Editor);

hacke2 commented Jun 7, 2016

我这边是展示的时候吧im对象转为原生,不知道这样有没有问题,,,:

export default connect(state => ({
    state: state.editor.toJSON()
}), (dispatch) => ({
    actions: bindActionCreators(editorAction, dispatch)
}))(Editor);
@hacke2

This comment has been minimized.

Show comment
Hide comment
@hacke2

hacke2 Jun 7, 2016

https://github.com/kolodny/immutability-helper

发现这个库也是不错的选择,基于react-addons-update,并且也可以在上面进行命令封装

hacke2 commented Jun 7, 2016

https://github.com/kolodny/immutability-helper

发现这个库也是不错的选择,基于react-addons-update,并且也可以在上面进行命令封装

@ah-kevin

This comment has been minimized.

Show comment
Hide comment
@ah-kevin

ah-kevin Jun 9, 2016

@camsong 我也用了react-immutable-render-mixin 这个组件 用的注解形式的~~可是他不生效 还是要自己写shouldComponentUpdate 为什么

ah-kevin commented Jun 9, 2016

@camsong 我也用了react-immutable-render-mixin 这个组件 用的注解形式的~~可是他不生效 还是要自己写shouldComponentUpdate 为什么

@wZi

This comment has been minimized.

Show comment
Hide comment
@wZi

wZi Jun 14, 2016

谢谢!

wZi commented Jun 14, 2016

谢谢!

@nepaul

This comment has been minimized.

Show comment
Hide comment

nepaul commented Jun 15, 2016

好文

@camsong

This comment has been minimized.

Show comment
Hide comment
@camsong

camsong Jul 8, 2016

Owner

@laiqun photoshop 逐帧编辑

Owner

camsong commented Jul 8, 2016

@laiqun photoshop 逐帧编辑

@Aijunwei

This comment has been minimized.

Show comment
Hide comment
@Aijunwei

Aijunwei Jul 15, 2016

感觉shouldComponentUpdate这里还是有点问题吧:

if (thisProps[key] !== nextProps[key] || is(thisProps[key], nextProps[key])) {
      return true;
    }

既然是imutable的数据,就算不全等后面也可能is也可能会返回true的,是不是该这样写:

if(!is(thisProps[key],nextProps[key]){
return true
}

感觉shouldComponentUpdate这里还是有点问题吧:

if (thisProps[key] !== nextProps[key] || is(thisProps[key], nextProps[key])) {
      return true;
    }

既然是imutable的数据,就算不全等后面也可能is也可能会返回true的,是不是该这样写:

if(!is(thisProps[key],nextProps[key]){
return true
}
@camsong

This comment has been minimized.

Show comment
Hide comment
@camsong

camsong Jul 15, 2016

Owner

@Aijunwei 对的,谢谢指正。https://github.com/facebook/immutable-js/blob/master/src/is.js#L65 第一行就是全等比较

Owner

camsong commented Jul 15, 2016

@Aijunwei 对的,谢谢指正。https://github.com/facebook/immutable-js/blob/master/src/is.js#L65 第一行就是全等比较

@shikelong

This comment has been minimized.

Show comment
Hide comment
@shikelong

shikelong Oct 9, 2016

@hacke2

你这样把prop提供给component的时候 把im对象转为Pure对象的形式。 实际项目中的使用效果如何?

@hacke2

你这样把prop提供给component的时候 把im对象转为Pure对象的形式。 实际项目中的使用效果如何?

@hacke2

This comment has been minimized.

Show comment
Hide comment
@hacke2

hacke2 Oct 10, 2016

@shikelong 可以正常运行,但是用 react 做我那个项目实在是太复杂了,弃坑了。。

hacke2 commented Oct 10, 2016

@shikelong 可以正常运行,但是用 react 做我那个项目实在是太复杂了,弃坑了。。

@windyrain

This comment has been minimized.

Show comment
Hide comment
@windyrain

windyrain Oct 21, 2016

shouldComponentUpdate 中props判断中,没有加!,应该是笔误,希望修改一下,一开始没看评论,直接使用了上面代码,

shouldComponentUpdate 中props判断中,没有加!,应该是笔误,希望修改一下,一开始没看评论,直接使用了上面代码,

@camsong

This comment has been minimized.

Show comment
Hide comment
Owner

camsong commented Oct 21, 2016

@windyrain fixed

@gzhappysky

This comment has been minimized.

Show comment
Hide comment
@gzhappysky

gzhappysky Nov 1, 2016

感谢,真是好文

感谢,真是好文

@xiaxiazhu xiaxiazhu referenced this issue Nov 26, 2016

Open

immutable #6

@Aaronphy

This comment has been minimized.

Show comment
Hide comment
@Aaronphy

Aaronphy Nov 28, 2016

最近碰到了一些 无序数组的坑,感觉state 必须 immutable~~好文 ,多看几遍~

最近碰到了一些 无序数组的坑,感觉state 必须 immutable~~好文 ,多看几遍~

@Pines-Cheng

This comment has been minimized.

Show comment
Hide comment
@Pines-Cheng

Pines-Cheng Dec 12, 2016

好文,准备尝试。

好文,准备尝试。

@1renhaO

This comment has been minimized.

Show comment
Hide comment
@1renhaO

1renhaO Dec 18, 2016

我看到的关于immutable中写的比较好的

1renhaO commented Dec 18, 2016

我看到的关于immutable中写的比较好的

@windsome

This comment has been minimized.

Show comment
Hide comment

good

@LeoEatle

This comment has been minimized.

Show comment
Hide comment
@LeoEatle

LeoEatle Feb 20, 2017

啊,明白了immutable pure render在Redux的重要作用

啊,明白了immutable pure render在Redux的重要作用

@zhoushan1

This comment has been minimized.

Show comment
Hide comment

nice!!!

@lugy90

This comment has been minimized.

Show comment
Hide comment
@lugy90

lugy90 May 24, 2017

关于React优化,shouldComponentUpdate那一块,我有个地方没有理解,在本文 实践 部分, 有一块针对shouldComponentUpdate的代码, 这块代码我理解是,如果prop state 和 nextProp nextState 有任何不同就返回true, 如没有不同就返回false, 我有个问题是,如果有任何不同,返回true,React还是会返回整个虚拟DOM吗,我的理解是,if判断后返回true 和 整个shouldComponentUpdate默认返回true是一样的,如果这样,React还是返回整张虚拟DOM,是否if判断后返回true,React就只返回改变路径的虚拟DOM,这一块,React会自己处理吗(我不清楚,shouldComponentUpdate是针对某个节点返回true或false还是针对整个DOM,返回一个true或false)

lugy90 commented May 24, 2017

关于React优化,shouldComponentUpdate那一块,我有个地方没有理解,在本文 实践 部分, 有一块针对shouldComponentUpdate的代码, 这块代码我理解是,如果prop state 和 nextProp nextState 有任何不同就返回true, 如没有不同就返回false, 我有个问题是,如果有任何不同,返回true,React还是会返回整个虚拟DOM吗,我的理解是,if判断后返回true 和 整个shouldComponentUpdate默认返回true是一样的,如果这样,React还是返回整张虚拟DOM,是否if判断后返回true,React就只返回改变路径的虚拟DOM,这一块,React会自己处理吗(我不清楚,shouldComponentUpdate是针对某个节点返回true或false还是针对整个DOM,返回一个true或false)

@jianzhou520

This comment has been minimized.

Show comment
Hide comment

赞一个

@Mmzer

This comment has been minimized.

Show comment
Hide comment
@Mmzer

Mmzer Jul 7, 2017

准备尝试一下

Mmzer commented Jul 7, 2017

准备尝试一下

@liwenlong

This comment has been minimized.

Show comment
Hide comment
@liwenlong

liwenlong Aug 11, 2017

初步看了一遍,确实和传统对象思路不太一致,还不太理解。Immutable是为了解决,复杂业务中数值被莫名的组件乱改的风险么?看来还需要加深业务需求的理解。

初步看了一遍,确实和传统对象思路不太一致,还不太理解。Immutable是为了解决,复杂业务中数值被莫名的组件乱改的风险么?看来还需要加深业务需求的理解。

@guimeisang guimeisang referenced this issue Aug 25, 2017

Closed

immutabel #7

@tiodot tiodot referenced this issue Sep 9, 2017

Open

React相关 #17

@Phieo

This comment has been minimized.

Show comment
Hide comment
@Phieo

Phieo Sep 19, 2017

那你默认nextProps[key]是简单数据类型了吗?

Phieo commented Sep 19, 2017

那你默认nextProps[key]是简单数据类型了吗?

@wQueryLoveMm

This comment has been minimized.

Show comment
Hide comment
@wQueryLoveMm

wQueryLoveMm Sep 22, 2017

非常详细 对于react新手来说太好了~~

非常详细 对于react新手来说太好了~~

@oychao

This comment has been minimized.

Show comment
Hide comment
@oychao

oychao Sep 28, 2017

可以可以,感谢作者~

oychao commented Sep 28, 2017

可以可以,感谢作者~

@xuchenchenBoy

This comment has been minimized.

Show comment
Hide comment
@xuchenchenBoy

xuchenchenBoy Oct 17, 2017

Immutable.min.js 压缩版本的大小有50多k,为什么作者说16k?

Immutable.min.js 压缩版本的大小有50多k,为什么作者说16k?

@NameIsEward

This comment has been minimized.

Show comment
Hide comment

好东西

@WangYang-Rex

This comment has been minimized.

Show comment
Hide comment

mark

@tageecc

This comment has been minimized.

Show comment
Hide comment
@tageecc

tageecc Nov 2, 2017

this.setState({ data: this.state.data.update('times', v => v + 1) });
// 这时的 times 并不会改变
console.log(this.state.data.get('times'));

setState不是异步的吗

tageecc commented Nov 2, 2017

this.setState({ data: this.state.data.update('times', v => v + 1) });
// 这时的 times 并不会改变
console.log(this.state.data.get('times'));

setState不是异步的吗

@SKing7

This comment has been minimized.

Show comment
Hide comment
@SKing7

SKing7 Jan 19, 2018

immutable 其实在很多项目中没必要用。数据变化的层级不会很深。使用shallowCompare就可以。

SKing7 commented Jan 19, 2018

immutable 其实在很多项目中没必要用。数据变化的层级不会很深。使用shallowCompare就可以。

@dengwanc

This comment has been minimized.

Show comment
Hide comment
@dengwanc

dengwanc Mar 27, 2018

千言万语,看源码

千言万语,看源码

@AmamiRyoin

This comment has been minimized.

Show comment
Hide comment
@AmamiRyoin

AmamiRyoin Mar 29, 2018

xaq tiq0_uj4zahoj9934kp
这边就算你不深拷贝打印出来也不会+1吧,除非是写在setState的回调里

xaq tiq0_uj4zahoj9934kp
这边就算你不深拷贝打印出来也不会+1吧,除非是写在setState的回调里

@lyyh lyyh referenced this issue Mar 31, 2018

Open

Immutable #25

@lz-lee

This comment has been minimized.

Show comment
Hide comment
@lz-lee

lz-lee Apr 5, 2018

for (const key in nextProps) {
    if (!is(thisProps[key], nextProps[key])) {
      return true;
    }
  }

  for (const key in nextState) {
    if (thisState[key] !== nextState[key] || !is(thisState[key], nextState[key])) {
      return true;
    }
  }

image
代码里是比较的 value 吧?不是 key
如果是比较key, 那就是这样写了啊

if (!is(key, key)) {
...
}

笔误嘛?

lz-lee commented Apr 5, 2018

for (const key in nextProps) {
    if (!is(thisProps[key], nextProps[key])) {
      return true;
    }
  }

  for (const key in nextState) {
    if (thisState[key] !== nextState[key] || !is(thisState[key], nextState[key])) {
      return true;
    }
  }

image
代码里是比较的 value 吧?不是 key
如果是比较key, 那就是这样写了啊

if (!is(key, key)) {
...
}

笔误嘛?

@ddduanlian

This comment has been minimized.

Show comment
Hide comment
@ddduanlian

ddduanlian Apr 26, 2018

《深入react技术栈》这本书是楼主写的吗?

《深入react技术栈》这本书是楼主写的吗?

@cunjieliu

This comment has been minimized.

Show comment
Hide comment

get

@camsong

This comment has been minimized.

Show comment
Hide comment
@camsong

camsong May 12, 2018

Owner

@ddduanlian 部分章节是我写的,多人合作完成

Owner

camsong commented May 12, 2018

@ddduanlian 部分章节是我写的,多人合作完成

@venoral

This comment has been minimized.

Show comment
Hide comment
@venoral

venoral May 27, 2018

excellent!!

venoral commented May 27, 2018

excellent!!

@AngusLius AngusLius referenced this issue May 30, 2018

Open

性能 #8

@TrustTheBoy

This comment has been minimized.

Show comment
Hide comment
@TrustTheBoy

TrustTheBoy Jun 1, 2018

shouldComponentUpdate中thisState[key]!==nextState[key] || !is(thisState[key],nextState[key])

thisState[key]!==nextState[key] 在嵌套多层数据的两个数据比较后会返回true, 所以是不是应该写成&&?
我已将我的案例上传到GitHub

演示效果请点击
请查看控制台打印信息

TrustTheBoy commented Jun 1, 2018

shouldComponentUpdate中thisState[key]!==nextState[key] || !is(thisState[key],nextState[key])

thisState[key]!==nextState[key] 在嵌套多层数据的两个数据比较后会返回true, 所以是不是应该写成&&?
我已将我的案例上传到GitHub

演示效果请点击
请查看控制台打印信息

@fenghuizhang

This comment has been minimized.

Show comment
Hide comment
@fenghuizhang

fenghuizhang Jun 8, 2018

image
The description of the "deepClone is required on modify the state" is actually misinterpreting the intention of react. The official of react does not support the direct modification of the state but only through the setState to modify the state.

fenghuizhang commented Jun 8, 2018

image
The description of the "deepClone is required on modify the state" is actually misinterpreting the intention of react. The official of react does not support the direct modification of the state but only through the setState to modify the state.

@LJJCherry

This comment has been minimized.

Show comment
Hide comment
@LJJCherry

LJJCherry Jul 31, 2018

@chenmnkken 没看懂哎。。为什么说setState的时候希望state是一个纯粹的对象。。但是例子里面用的不就是immutable对象,我是哪里理解错了
image

@chenmnkken 没看懂哎。。为什么说setState的时候希望state是一个纯粹的对象。。但是例子里面用的不就是immutable对象,我是哪里理解错了
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment