Reputation: 74
In my react/redux project, I have an action that sorts an array:
case 'SORT_BY_NAME':
var newList = state.list; //.slice()
newList.sort(function(a,b){
if (a.name > b.name){
return 1;
} else if (a.name < b.name){
return -1;
} else {
return 0;
}
});
return Object.assign({}, state, { list: newList } );
The initial rendering was fine. But the sort action failed to result in my component's render method being invoked again, so the data in the UI never appeared sorted.
The architecture of my project is similar to the Reddit example in the Redux docs. However, I also use react-redux's connect with mapStateToProps. Below is a stripped down version of my component design:
class MyComponent extends React.Component{
render(){
<ul>
{list.map(item =>
<li key={item.id}>
{item.name}
</li>
)}
</ul>
}
}
function mapStateToProps(state){
return {
list: state.list;
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(MyComponent)
By setting a breakpoint within mapStateToProps, it looks as if the state is being set/changed properly; according to the Redux devtools in the Chrome debugger, the store looks as I think it should.
My project is too large to create a demo fiddle that exactly reproduces my problem. When I attempted to create a minimally-sized fiddle to reproduce the issue, I was further perplexed because the issue does NOT occur when I am not using Redux's connect. Link to fiddle.
To summarize, my question is why the sort was not taking effect when using mapStateToProps. My best guess is that if my sort action mutates the previous state so that the new state matches the previous state, then there is no variance that requires a re-rendering. Perhaps mapStateToProps compares previous and new states, and it doesn't compare new props to props' representation in the DOM.
Upvotes: 1
Views: 3075
Reputation: 268255
React Redux connect()
is heavily optimized and operates under the assumption that mapStateToProps
is a pure function.
By calling state.list.sort()
you are mutating the store state with is not allowed in Redux. Generally it’s a good idea to remember which methods are mutating, and which are not. For example, splice()
is mutation but slice()
isn’t; push()
is mutating but concat()
isn’t. You should never use mutating methods with the state obtained from the store.
You may also look at something like redux-immutable-state-invariant to make these cases easier to detect, or use Immutable collections for JavaScript or seamless-immutable to enforce immutability. This is optional and up to you.
Upvotes: 6