shouldComponentUpdate + deepEqual和数组

时间:2015-11-04 13:25:48

标签: javascript reactjs flux

问题: shouldComponentUpdate使用this.state检索以前的状态,如果您继续引用UserList处的数组,则更新数组实体UserStore

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;
};

UserList.react.js

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);

UsersStore.js

......
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;
}

@taggon解决方案

感谢taggon,现在我知道如何让shouldComponentUpdate保持对先前状态的引用:

UsersStore.js

......
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;
}

2 个答案:

答案 0 :(得分:1)

我认为问题出在商店里。 只要状态发生变化,商店就会更好地创建另一个数组。

例如,将商店视为数组:

var store = [ ];

export default store;

您可能想要编写add()函数,如下所示:

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

我希望这会对你有所帮助。

答案 1 :(得分:0)

如果您的道具是不可变的,您可以安全,轻松地通过参考比较数据。你可以看一下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>
    );
  }
}

https://facebook.github.io/immutable-js/