Javascript 应更新组件+;深度相等和数组
问题:Javascript 应更新组件+;深度相等和数组,javascript,reactjs,flux,Javascript,Reactjs,Flux,问题:shouldComponentUpdate使用此状态检索以前的状态。如果在用户列表中保持对数组的引用,并在用户存储中更新数组实体,则该状态将不起作用 purendermixin.js const deepEqual = require('deep-equal'); module.exports = function pureRenderMixin(Component) { Component.prototype.shouldComponentUpdate = function(n
shouldComponentUpdate
使用此状态检索以前的状态。如果在用户列表中保持对数组的引用,并在用户存储中更新数组实体,则该状态将不起作用
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 UserList extends React.Component {
constructor(props) {
super(props);
this._onChange = this._onChange.bind(this);
}
componentWillMount() {
UsersStore.addChangeListener(this._onChange);
}
_onChange() {
this.setState({userList: UsersStore.getState()});
}
}
module.exports = PureRenderMixin(UserList);
......
getState() { return _userList; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
//!!!!!!!!!!!!!!
//PROBLEM: since UserList.react keep userList reference, there is no way to retrieve previous state inside shouldComponentUpdate
_userList[action.index].flag = action.flag;
UsersStore.emitChange();
break;
}
......
getState() { return _userList; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
//SOLUTION: copy an array, so there will be two versions of _userList[action.index]
_userList = _.map(_userList, _.clone);
_userList[action.index].flag = action.flag;
UsersStore.emitChange();
break;
}
UserList.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 UserList extends React.Component {
constructor(props) {
super(props);
this._onChange = this._onChange.bind(this);
}
componentWillMount() {
UsersStore.addChangeListener(this._onChange);
}
_onChange() {
this.setState({userList: UsersStore.getState()});
}
}
module.exports = PureRenderMixin(UserList);
......
getState() { return _userList; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
//!!!!!!!!!!!!!!
//PROBLEM: since UserList.react keep userList reference, there is no way to retrieve previous state inside shouldComponentUpdate
_userList[action.index].flag = action.flag;
UsersStore.emitChange();
break;
}
......
getState() { return _userList; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
//SOLUTION: copy an array, so there will be two versions of _userList[action.index]
_userList = _.map(_userList, _.clone);
_userList[action.index].flag = action.flag;
UsersStore.emitChange();
break;
}
UsersStore.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 UserList extends React.Component {
constructor(props) {
super(props);
this._onChange = this._onChange.bind(this);
}
componentWillMount() {
UsersStore.addChangeListener(this._onChange);
}
_onChange() {
this.setState({userList: UsersStore.getState()});
}
}
module.exports = PureRenderMixin(UserList);
......
getState() { return _userList; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
//!!!!!!!!!!!!!!
//PROBLEM: since UserList.react keep userList reference, there is no way to retrieve previous state inside shouldComponentUpdate
_userList[action.index].flag = action.flag;
UsersStore.emitChange();
break;
}
......
getState() { return _userList; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
//SOLUTION: copy an array, so there will be two versions of _userList[action.index]
_userList = _.map(_userList, _.clone);
_userList[action.index].flag = action.flag;
UsersStore.emitChange();
break;
}
@塔贡溶液
多亏了taggon,现在我知道了如何使shouldComponentUpdate
保持对以前状态的引用:
UsersStore.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 UserList extends React.Component {
constructor(props) {
super(props);
this._onChange = this._onChange.bind(this);
}
componentWillMount() {
UsersStore.addChangeListener(this._onChange);
}
_onChange() {
this.setState({userList: UsersStore.getState()});
}
}
module.exports = PureRenderMixin(UserList);
......
getState() { return _userList; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
//!!!!!!!!!!!!!!
//PROBLEM: since UserList.react keep userList reference, there is no way to retrieve previous state inside shouldComponentUpdate
_userList[action.index].flag = action.flag;
UsersStore.emitChange();
break;
}
......
getState() { return _userList; }
switch(action.type) {
case ActionTypes.UPDATE_USER_FLAG:
//SOLUTION: copy an array, so there will be two versions of _userList[action.index]
_userList = _.map(_userList, _.clone);
_userList[action.index].flag = action.flag;
UsersStore.emitChange();
break;
}
如果您的道具是不可变的,那么您可以通过引用安全轻松地比较数据。您可以看看immutablejs
class ProductStore extends ReduceStore {
getInitialState() {
return Immutable.OrderedMap({1: new Product('react', 'flux'), 2: new Product('angular', 'mvc')});
}
reduce (state, action) {
switch (action.type) {
case 'product/item-selected':
return state.map((product)=> {
return product.set('selected', product.id === action.id);
});
case 'product/search':
let alldata = this.getInitialState();
return alldata.filter((product)=> {
return product.name.indexOf(action.value) !== -1;
});
default:
return state;
}
}
}
export default class ProductDetail extends Component {
shouldComponentUpdate(nextProps) {
return this.props.product !== nextProps.product;
}
render() {
const {product} = this.props;
return (
<div className="product-detail">
<div className="product-name">
{product.name}
</div>
<div className="product-type">
{product.type}
</div>
</div>
);
}
}
class ProductStore扩展了ReduceStore{
getInitialState(){
返回Immutable.OrderedMap({1:new Product('react','flux'),2:new Product('angular','mvc'));
}
减少(状态、行动){
开关(动作类型){
案例“所选产品/项目”:
返回状态.map((产品)=>{
返回product.set('selected',product.id==action.id);
});
案例“产品/搜索”:
让alldata=this.getInitialState();
返回alldata.filter((产品)=>{
返回product.name.indexOf(action.value)!=-1;
});
违约:
返回状态;
}
}
}
导出默认类ProductDetail扩展组件{
应更新组件(下一步){
返回this.props.product!==nextrops.product;
}
render(){
const{product}=this.props;
返回(
{product.name}
{product.type}
);
}
}
我想问题出在商店里。
存储区最好在其状态更改时创建另一个数组
例如,将存储视为一个数组:
var store = [ ];
export default store;
您可能希望编写如下函数:
export function add(newItem) {
store = [ ...store, newItem ];
// or write this in es5
store = store.concat([newItem]);
// trigger change event or dispatch an action here
}
类似地,remove()
函数可以是:
export remove(index) {
store = [ ...store.slice(0, index), ...store.slice(index+1) ];
// trigger change event or dispatch an action here
}
这样,每当存储发生更改时,存储就会取消对组件状态的引用。这使得shouldComponentUpdate()
返回true
我希望这对您有所帮助。问题是如何在shouldComponentUpdate
中获取对以前状态的引用组件的数据应该通过道具设置,您应该让视图控制器aka top component来控制数据状态,在我的示例中,我有一个名为App
的组件来控制存储,并通过props将数据传递给我的componetProductDetail
,我为什么要将数据保存在props中?这将如何改变现状?我保持这种状态是因为它是动态的。该数组实际上是一个用户列表,可以跟踪/取消跟踪、更改其状态等等。我应该在飞行图上反映这些变化那么你的视图控制器在哪里?您应该有一个名为UserList
的组件来呈现列表,视图控制器保持状态,它应该通过props
将UserList传递给组件UserList
,您的UserList可以是一个没有out state的纯组件,我有它。我只是试图简化代码来描述这个问题。请看塔贡的回答,看起来他解决了我的问题。