Javascript 反应:使用或不使用Immutable.js
在使用React.js时,我一直在寻找不可变的.js动机。据我所知,React.js应该保证属性的不变性。但是,我可以更改视图属性:Javascript 反应:使用或不使用Immutable.js,javascript,reactjs,immutable.js,Javascript,Reactjs,Immutable.js,在使用React.js时,我一直在寻找不可变的.js动机。据我所知,React.js应该保证属性的不变性。但是,我可以更改视图属性: immutable.js增强与PureRenderMixin的反应性能 purendermixin的来源: var ReactComponentWithPureRenderMixin = { shouldComponentUpdate: function(nextProps, nextState) { return !shallowEqual(this
immutable.js增强与PureRenderMixin的反应性能 purendermixin的来源:
var ReactComponentWithPureRenderMixin = {
shouldComponentUpdate: function(nextProps, nextState) {
return !shallowEqual(this.props, nextProps) ||
!shallowEqual(this.state, nextState);
}
};
使用immutable.js比较shallowEqual中的两个对象非常快在使用react pure rendering面对所有RAKE后,我想说的是
immutable.js
并不是提供deepEqual方法。要点是在每次修改时克隆状态。
为什么每次修改都需要克隆状态
在视图的状态只包含原始值之前,一切都很顺利。但有一种情况可能会发生,那就是数组或复杂对象树
假设您有一个视图YourView
,它从存储YourStore
获取一个数组。您不想使用Immutable.js
,只需要包含Node.LS的deepEqual
。例如:
purendermixin.js
const deepEqual = require('deep-equal');
module.exports = function pureRenderMixin(Component) {
Component.prototype.shouldComponentUpdate = function(nextProps, nextState) {
return !deepEqual(this.props, nextProps) || !deepEqual(this.state, nextState);
};
return Component;
};
class YourView extends React.Component {
constructor(props) {
super(props);
this._onChange = this._onChange.bind(this);
}
componentWillMount() {
YourStore.addChangeListener(this._onChange);
}
_onChange() {
this.setState({array: YourStore.getArray()});
}
}
module.exports = PureRenderMixin(YourView);
......
getArray() { return _array; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
_array[action.index].value= action.flag; // BUG!!!
YourStore.emitChange();
break;
}
......
getArray() { return _array; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
_array = _.cloneDeep(_array); // FIXED, now the previous state will differ from the new one
_array[action.index].value= action.flag; // BUG!!!
YourStore.emitChange();
break;
}
YourView.react.js
const deepEqual = require('deep-equal');
module.exports = function pureRenderMixin(Component) {
Component.prototype.shouldComponentUpdate = function(nextProps, nextState) {
return !deepEqual(this.props, nextProps) || !deepEqual(this.state, nextState);
};
return Component;
};
class YourView extends React.Component {
constructor(props) {
super(props);
this._onChange = this._onChange.bind(this);
}
componentWillMount() {
YourStore.addChangeListener(this._onChange);
}
_onChange() {
this.setState({array: YourStore.getArray()});
}
}
module.exports = PureRenderMixin(YourView);
......
getArray() { return _array; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
_array[action.index].value= action.flag; // BUG!!!
YourStore.emitChange();
break;
}
......
getArray() { return _array; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
_array = _.cloneDeep(_array); // FIXED, now the previous state will differ from the new one
_array[action.index].value= action.flag; // BUG!!!
YourStore.emitChange();
break;
}
YourStore.js
const deepEqual = require('deep-equal');
module.exports = function pureRenderMixin(Component) {
Component.prototype.shouldComponentUpdate = function(nextProps, nextState) {
return !deepEqual(this.props, nextProps) || !deepEqual(this.state, nextState);
};
return Component;
};
class YourView extends React.Component {
constructor(props) {
super(props);
this._onChange = this._onChange.bind(this);
}
componentWillMount() {
YourStore.addChangeListener(this._onChange);
}
_onChange() {
this.setState({array: YourStore.getArray()});
}
}
module.exports = PureRenderMixin(YourView);
......
getArray() { return _array; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
_array[action.index].value= action.flag; // BUG!!!
YourStore.emitChange();
break;
}
......
getArray() { return _array; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
_array = _.cloneDeep(_array); // FIXED, now the previous state will differ from the new one
_array[action.index].value= action.flag; // BUG!!!
YourStore.emitChange();
break;
}
问题#1:shouldComponentUpdate返回false而不是true您希望\u数组[action.index].value=action.flag
将更新您的视图
,但它不会。这不是因为shouldComponentUpdate
将返回false
原因是数组只是一个引用,在this.setState({array:YourStore.getArray()})
this.state.array(以前的状态)的时候也会更新。这意味着内部应该组件更新方法此状态和下一状态参考将指向同一对象
问题1#解决方案:
您需要在更新数组引用之前复制它(即在lodash的帮助下):
YourStore.js
const deepEqual = require('deep-equal');
module.exports = function pureRenderMixin(Component) {
Component.prototype.shouldComponentUpdate = function(nextProps, nextState) {
return !deepEqual(this.props, nextProps) || !deepEqual(this.state, nextState);
};
return Component;
};
class YourView extends React.Component {
constructor(props) {
super(props);
this._onChange = this._onChange.bind(this);
}
componentWillMount() {
YourStore.addChangeListener(this._onChange);
}
_onChange() {
this.setState({array: YourStore.getArray()});
}
}
module.exports = PureRenderMixin(YourView);
......
getArray() { return _array; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
_array[action.index].value= action.flag; // BUG!!!
YourStore.emitChange();
break;
}
......
getArray() { return _array; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
_array = _.cloneDeep(_array); // FIXED, now the previous state will differ from the new one
_array[action.index].value= action.flag; // BUG!!!
YourStore.emitChange();
break;
}
问题#2:有时需要多次克隆阵列,代码出错
假设您需要更新if
语句中数组的多个值:
case ActionTypes.UPDATE_USER_FLAG:
// You can't clone the _array once, because you don't know which conditions will be executed
// Also conditions may not be executed at all, so you can't clone the _array outside of if statements
if (someCondition) {
_array = _.cloneDeep(_array);
_array[someIndex].value= action.flag;
}
if (anotherCondition) {
_array = _.cloneDeep(_array);
_array[anotherIndex].value= action.flag;
}
YourStore.emitChange();
break;
问题#2解决方案:使用Immutable.js
。好处:
它有清晰的界面,让你的大学明白每次都应该克隆这个州
它有批量更新,所以您不必担心多次克隆阵列
AFAIK道具在v0.14中只是“不可变”(对象实际上是冻结的)。演示使用v0.13。编辑:是的:@FelixKling在v0.14中使用Immutable.js
的动机是什么?@limelights是的,但是如果我可以使用习惯的js API,并且没有更多的理由切换-我不会使用Immutable.js
如果希望值本身是不可变的,你会使用Immutable.js,例如,如果您将一个复杂的数据结构作为道具传递,并且该结构应该是不可变的。@FelixKling很好!这对我来说听起来很奇怪,React家伙只冻结道具引用,而不冻结其内部