在面对所有使用 react 纯渲染的rakes 之后,我想说这Immutable.js
与提供 deepEqual 方法无关。重点是在每次修改时克隆状态。
为什么每次修改都需要克隆状态?
一切顺利,直到视图的状态仅由原始值组成。但可能发生的时刻是一个数组或复杂的对象树。
假设您有一个YourView
从 store 获取数组的视图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 返回 false 而不是 true您期望它_array[action.index].value = action.flag;
会更新YourView
,但事实并非如此。它不会因为shouldComponentUpdate
会返回false
。
原因是array只是一个引用,此时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,代码会出错
假设您需要更新_array
内部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
. 好处:
- 它具有清晰的界面,并让您的大学清楚每次都应该克隆状态
- 它具有批量更新,因此您不必担心多次克隆数组