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将数据传递给我的componet
ProductDetail
,我为什么要将数据保存在props中?这将如何改变现状?我保持这种状态是因为它是动态的。该数组实际上是一个用户列表,可以跟踪/取消跟踪、更改其状态等等。我应该在飞行图上反映这些变化那么你的视图控制器在哪里?您应该有一个名为
UserList
的组件来呈现列表,视图控制器保持状态,它应该通过
props
将UserList传递给组件
UserList
,您的UserList可以是一个没有out state的纯组件,我有它。我只是试图简化代码来描述这个问题。请看塔贡的回答,看起来他解决了我的问题。