Problem: shouldComponentUpdate
retrieves previous state with this.state
, that doesn't work if you keep reference to array at UserList
, and update array entity at 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;
}
thanks to taggon, now I know how to make shouldComponentUpdate
keep the reference to previous state:
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;
}
I think the problem is in the store. The store would be better to create another array whenever its state is changed.
For example, think the store as an array:
var store = [ ];
export default store;
You may want to write add()
function like this:
export function add(newItem) {
store = [ ...store, newItem ];
// or write this in es5
store = store.concat([newItem]);
// trigger change event or dispatch an action here
}
Likewise, remove()
function can be:
export remove(index) {
store = [ ...store.slice(0, index), ...store.slice(index+1) ];
// trigger change event or dispatch an action here
}
In this way, the store dereference the component's state whenever the store is changed. This makesshouldComponentUpdate()
return true
.
I hope this helps you.