Reputation: 7232
I have a component which shows a list of names fetched from the Redux store. The component looks like this:
class Details extends React.Component {
constructor (props) {
super(props);
}
render () {
const listName = [...this.props.listName];
return (
<div className="container detailsBox">
<p>Details Grid:</p>
{listName ? (
listName.map((el, index) => {
return (
<li key={index}>
{el}
</li>
)
})
): null}
</div>
)
}
}
const mapStateToProps = (state) => {
return {
listName: state.listName
}
}
export default connect(mapStateToProps)(Details);
Notice here I only map the listName
from the store. But the code does not display the <li>
with the elements of listName
even when logging in console shows listName
is populated with data
But data shows as expected when the name
is also fetched from the store, with this modification in mapStateToProps
:
const mapStateToProps = (state) => {
return {
listName: state.listName,
name: state.name
}
}
I am befuddled as well as curious to know why the code behaves in this unexpected way? What am I missing here?
The reducer code looks like this:
import { UPDATE_NAME, ADD_NAME } from '../actions/addName.action';
const initialState = {
name: '',
listName: new Set()
}
function rootReducer (state = initialState, action) {
switch (action.type) {
case ADD_NAME:
return {
name: '',
listName: state.listName.add(action.payload)
}
case UPDATE_NAME:
return {
...state,
name: action.payload
}
default:
return state;
}
}
export default rootReducer;
and the actions like this:
export const ADD_NAME = 'ADD_NAME';
export const UPDATE_NAME = 'UPDATE_NAME';
export function addName (data) {
return {
type: ADD_NAME,
payload: data
}
}
export function updateName (name) {
return {
type: UPDATE_NAME,
payload: name
}
}
Upvotes: 0
Views: 66
Reputation: 169
This is happens because you mutate the state. When you mutate listNames
it still points to the same object in memory, and react thinks that nothing is changed, while the contents of listNames
is changed. You should return a new object.
case ADD_NAME:
return {
name: '',
listName: new Set([...state.listName, action.payload]),
}
But it is not recommended to use Set
s in reducers. Instead you can store your listNames
as an Array and use lodash union
function to have only unique values.
import { union } from 'lodash';
const initialState = {
name: '',
listName: []
}
// some code
case ADD_NAME:
return {
name: '',
listName: union(state.listNames, action.payload)
}
Upvotes: 2
Reputation: 52
You can instead use an object to hold the listName and then recreate the structure of your state into a new object and then return.
const initialState = {
name: '',
listName: {}
}
case ADD_NAME:
return {
name: '',
listName: {...state.listName, action.payload}
}
Upvotes: 0