Reputation: 945
I have a strange problem with Redux and React.
The state changes properly and in mapStateToProps
I also get the right new state but after the mapping the component will not rerender.
This way, the component doesn't rerender:
import React, { Component } from 'react';
import { connect } from 'react-redux';
class ListItem extends Component {
render() {
return (<li>{this.props.item.text}</li>);
}
}
const mapStateToProps = (state, ownProps) => {
return {
item: state.test.byID[ownProps.itemID]
};
}
export default connect(mapStateToProps)(ListItem);
But if I split the item the components rerender:
import React, { Component } from 'react';
import { connect } from 'react-redux';
class ListItem extends Component {
render() {
return(<li>{this.props.text}</li>);
}
}
const mapStateToProps = (state, ownProps) => {
return {
id: state.test.byID[ownProps.itemID].id,
text: state.test.byID[ownProps.itemID].text
};
}
export default connect(mapStateToProps)(ListItem);
I have no clue why.
Reducer:
const startState = {
byID: {
'a1': {id: 'a1', text: 'test1'},
'a2': {id: 'a2', text: 'test2'},
'a3': {id: 'a3', text: 'test3'},
'a4': {id: 'a4', text: 'test4'},
'a5': {id: 'a5', text: 'test5'},
'a6': {id: 'a6', text: 'test6'},
'a7': {id: 'a7', text: 'test7'},
},
all: ['a1', 'a2','a3', 'a4', 'a5', 'a6', 'a7']
};
export default function reducer(state = startState, action) {
switch (action.type) {
case 'ADD_TEXT':
const newState = {...state};
newState.byID[action.id].text = action.text;
return newState
default:
return state;
}
}
Any ideas?
Upvotes: 1
Views: 3399
Reputation: 3021
Assuming you are changing the text
field in one of byID
array's objects. With your code:
newState.byID[action.id].text = action.text;
You are mutating your state, therefore React might have problems with recognising changes since the reference of object in item
prop does not change, only it's properties. If there is made shallow check, it simply won't re-render as it "suppose" object does not change at all.
In the second scenario you are returning prop text
which is string type, so there won't be shallow check like with object, and equal comparison ===
will distinguish change and properly re-render component.
For more clarification you might want to look at Immutability in React.
The idea of maintaining immutability with spread operator:
const newState = {...state};
Is okay for top-level reference, but not for nested children objects:
Object spread does a shallow copy of the object. Only the object itself is cloned, while nested instances are not cloned. An easy guide to object rest/spread properties in JavaScript
Although mutating object seems to be the most error prone part in your provided code, the Component
React class can deeply investigate object changes (PureComponent
does not) and the problem might be related to another issue.
Upvotes: 4