React:用还是不用 Immutable.js
React: use or not to use Immutable.js
我在使用 React.js 时寻找 Immutable.js 动力。据我了解 React.js 应该保证属性的不变性。但是,我可以更改视图属性 in this demo:
var Hello = React.createClass({
render: function() {
var item = { prop: 128 };
return <Test item={item} />;
}
});
var Test = React.createClass({
render: function() {
this.props.item = -2; // Don't throw any error
return <div>{this.props.item}</div>; // Returns -2 instead of object
}
});
React.render(<Hello name="World" />, document.getElementById('container'));
更新:感谢@FelixKling,现在我知道自 React v0.14(即将推出)以来属性将是不可变的。
问题:使用Immutable.js
和React v0.14
的动机是什么?
Update2: 我们真的可以改变 parent 的属性吗?在子组件中
let somePropVal = { a: 1 };
<SubComponent someProp={somePropVal} />
//....Then in SubComponent
this.props.someProp.a = 2; // somePropVal.a still will be `1` at parent element
immutable.js 使用 PureRenderMixin 提升反应性能
PureRenderMixin 来源:
var ReactComponentWithPureRenderMixin = {
shouldComponentUpdate: function(nextProps, nextState) {
return !shallowEqual(this.props, nextProps) ||
!shallowEqual(this.state, nextState);
}
};
与immutable.js比较shallowEqual中的两个对象非常快
在使用 React 纯渲染面对所有耙子之后,我想说 Immutable.js
与提供 deepEqual 方法无关。重点是在每次修改时克隆状态。
为什么每次修改都需要克隆状态?
一切顺利,直到视图的状态仅包含原始值。但是有一刻可能会发生它是一个数组或复杂的对象树。
假设您有一个视图 YourView
,它从商店 YourStore
获取一个数组。并且您不想使用 Immutable.js
,只需包含 Node.LS 的 deepEqual
。例如:
PureRenderMixin.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;
};
YourView.react.js
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);
YourStore.js
......
getArray() { return _array; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
_array[action.index].value= action.flag; // BUG!!!
YourStore.emitChange();
break;
}
问题 #1:shouldComponentUpdate return false 而不是 true 你期望 _array[action.index].value = action.flag;
会更新 YourView
,但它不会.不是因为 shouldComponentUpdate
会 return false
。
原因是数组只是一个引用,在this.setState({array: YourStore.getArray()})
的时刻this.state.array(之前的状态)也更新了。这意味着在 shouldComponentUpdate
方法内部 this.state
& nextState
refs 将指向同一个对象。
问题1#解决方法:
您需要在更新之前复制数组引用(即在 lodash 的帮助下):
YourStore.js
......
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:有时您需要多次克隆 _array,代码会出错
假设您需要在 if
语句中更新 _array
的多个值:
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
。好处:
- 它有清晰的界面,让你的大学清楚地知道每次应该克隆状态
- 它有批量更新,所以你不必担心多次克隆数组
我在使用 React.js 时寻找 Immutable.js 动力。据我了解 React.js 应该保证属性的不变性。但是,我可以更改视图属性 in this demo:
var Hello = React.createClass({
render: function() {
var item = { prop: 128 };
return <Test item={item} />;
}
});
var Test = React.createClass({
render: function() {
this.props.item = -2; // Don't throw any error
return <div>{this.props.item}</div>; // Returns -2 instead of object
}
});
React.render(<Hello name="World" />, document.getElementById('container'));
更新:感谢@FelixKling,现在我知道自 React v0.14(即将推出)以来属性将是不可变的。
问题:使用Immutable.js
和React v0.14
的动机是什么?
Update2: 我们真的可以改变 parent 的属性吗?在子组件中
let somePropVal = { a: 1 };
<SubComponent someProp={somePropVal} />
//....Then in SubComponent
this.props.someProp.a = 2; // somePropVal.a still will be `1` at parent element
immutable.js 使用 PureRenderMixin 提升反应性能
PureRenderMixin 来源:
var ReactComponentWithPureRenderMixin = {
shouldComponentUpdate: function(nextProps, nextState) {
return !shallowEqual(this.props, nextProps) ||
!shallowEqual(this.state, nextState);
}
};
与immutable.js比较shallowEqual中的两个对象非常快
在使用 React 纯渲染面对所有耙子之后,我想说 Immutable.js
与提供 deepEqual 方法无关。重点是在每次修改时克隆状态。
为什么每次修改都需要克隆状态?
一切顺利,直到视图的状态仅包含原始值。但是有一刻可能会发生它是一个数组或复杂的对象树。
假设您有一个视图 YourView
,它从商店 YourStore
获取一个数组。并且您不想使用 Immutable.js
,只需包含 Node.LS 的 deepEqual
。例如:
PureRenderMixin.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;
};
YourView.react.js
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);
YourStore.js
......
getArray() { return _array; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
_array[action.index].value= action.flag; // BUG!!!
YourStore.emitChange();
break;
}
问题 #1:shouldComponentUpdate return false 而不是 true 你期望 _array[action.index].value = action.flag;
会更新 YourView
,但它不会.不是因为 shouldComponentUpdate
会 return false
。
原因是数组只是一个引用,在this.setState({array: YourStore.getArray()})
的时刻this.state.array(之前的状态)也更新了。这意味着在 shouldComponentUpdate
方法内部 this.state
& nextState
refs 将指向同一个对象。
问题1#解决方法:
您需要在更新之前复制数组引用(即在 lodash 的帮助下):
YourStore.js
......
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:有时您需要多次克隆 _array,代码会出错
假设您需要在 if
语句中更新 _array
的多个值:
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
。好处:
- 它有清晰的界面,让你的大学清楚地知道每次应该克隆状态
- 它有批量更新,所以你不必担心多次克隆数组