我在使用 React.js 时寻找了 Immutable.js 的动机。据我了解,React.js 应该保证属性的不变性。但是,我可以更改 View 属性 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
一起使用的动机是什么?
更新2:我们真的可以改变父级的属性吗?在子组件中
let somePropVal = { a: 1 };
<SubComponent someProp={somePropVal} />
//....Then in SubComponent
this.props.someProp.a = 2; // somePropVal.a still will be `1` at parent element
最佳答案
在使用纯渲染进行 react 后,我想说 Immutable.js
并不是提供 deepEqual 方法。要点是在每次修改时克隆状态。
为什么需要在每次修改时克隆状态?
一切顺利,直到 View 的状态仅由原始值组成。但有一刻可能会发生它是一个数组或复杂的对象树。
假设您有一个 View 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 返回 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,代码会出现错误
假设您需要更新 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
。好处:
- 它具有清晰的界面,让您的大学清楚地知道每次都应该克隆状态
- 它具有批量更新功能,因此您不必担心多次克隆数组
关于javascript - react : use or not to use Immutable. js,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32719425/