For redux reducer step :
What if I only want to change one single property of initial_state. For example:
const INITIAL_STATE = {
signInInfo: {
signin: false,
name: "",
email: "",
...
},
changePassword: {
status: false,
...
}
...
};
Here I only want to set signInInfo.signin as true, currently , the only way I know is to input a complete "signInInfo" like :
case SIGNIN_USER:
return { ...state, signInInfo: action.payload.data };
action.payload.data is like:
{
signin: true,
name: "Qing",
email : ...
}
And another question is what if I want to set signInInfo.signin as false and meanwhile also need to change changePassword.status from false to true.
What should I do? Can anyone give me a hint?
Fairly simple (both questions):
case SIGNIN_USER: return {
...state,
signInInfo: {
...state.signInInfo,
signin: action.payload.signin
},
changePassword: {
...state.changePassword,
status: true
}
};
Related
I have a problem with my reducer and I need some help please :
In my payload i send {data,type}, and in my reducer I want to check the type to know in which place i will store my payload :
When the retrieve is done , my Reducer look like :
case GRID_GET_ADDITIONNAL_CONFIG_SUCCESS:
switch (action.payload.type) {
case 'compo':
return {
...state,
loading: false,
links: {
...state.links,
compo: [...state.links.compo, action.payload.data],
},
};
case 'traca':
return {
...state,
loading: false,
links: {
...state.links,
traca: [...state.links.traca, action.payload.data],
},
};
case 'revers':
return {
...state,
loading: false,
links: {
...state.links,
revers: [...state.links.revers, action.payload.data],
},
};
case 'externaldoc':
return {
...state,
loading: false,
links: {
...state.links,
external: [...state.links.external, action.payload.data],
},
};
default:
return state;
}
My output should be like this :
ReducerName : {
loading : false;
links : {
compo : { Here an array with all data with 'compo' type},
traca : { Here an array with all data with 'traca' type},
revers : { Here an array with all data with 'revers' type},
externaldoc : { Here an array with all data with 'externaldoc' type},
}
}
I think i've missed sommethings in my switch case, does anyone know what is the problem please ?
Thank you!
your dispatch function should look somehow like this ...
dispatch({
type: "some type",
payload : { data }
});
Then in your switch case should be like this:
switch (action.type) {
case 'compo':
return {
...state,
loading: false,
links: {
...state.links,
compo: [...state.links.compo, action.payload.data],
},
};
case 'traca':
return {
...state,
loading: false,
links: {
...state.links,
traca: [...state.links.traca, action.payload.data],
},
};
case 'revers':
return {
...state,
loading: false,
links: {
...state.links,
revers: [...state.links.revers, action.payload.data],
},
};
case 'externaldoc':
return {
...state,
loading: false,
links: {
...state.links,
external: [...state.links.external, action.payload.data],
},
};
default:
return state;
}
This is the common convention which is followed in industry .
I hope you got some key points to understand .
This must resolve your issue , try using this.
Also , try implementing dispatch function in this manner .
I have the following initial state for my react-redux
const initialState = {
logged: false,
user: null,
company: null,
}
When I first login, I set the state data
const data = action.payload.data;
const properties = action.payload.properties;
const notifications = action.payload.notifications;
return {
...state,
logged: true,
user: {
id: data.UserID,
firstName: data.UserFName,
lastName: data.UserLName,
email: data.UserEmail,
securityLevel: parseInt(data.SecurityLevelID),
notifications: {
multiProp: notifications.MultiProp && parseInt(notifications.MultiProp) === 1 ? false : true
}
},
company: {
id: data.CompanyID,
name: data.CompanyName,
email: data.ContactEmail,
leadSource: parseInt(data.LeadSourceCompanyID)
}
}
Then, at some point of my project, I need to update only user.notifications.multiProp, so I created a new Type called UPDMULTIPROP and I'm doing:
case Types.UPDMULTIPROP:
const userData = action.payload.data;
return {
...state,
user: {
notifications: {
multiProp: userData.notifications.MultiProp && parseInt(userData.notifications.MultiProp) === 1 ? false : true,
}
}
}
However, it set all the other user state to undefined. How can I update just the multiProp?
Thanks
user is also an object, to keep user state the same you should also spread the user.
case Types.UPDMULTIPROP:
const userData = action.payload.data;
return {
...state,
user: {
...state.user,
notifications: {
multiProp: userData.notifications.MultiProp && parseInt(userData.notifications.MultiProp) === 1 ? false : true,
}
}
}
To update nested object immutably you need to spread it again. Like
user : { ...state.user, notifications : someValue }
Like this.
I'm running into a strange problem where the initial state in one of my reducers is not accepting new values. I've been able to add new values to this initial state easily, but for some reason now new initial state entries come back as undefined when I mapStateToProps.
//REDUCER
const initialState = {
(...cutting out a bunch of state here),
collectionSearchResults: {
results: {},
loading: false,
loaded: false,
error: ''
},
collectionImage: {
image: '',
loading: false,
loaded: false,
error: '',
},
collectionBeingEdited: {
collectionId: '',
loading: false,
complete: false,
error: '',
test: '',
},
removeReport: {
loading: false,
}
}
//INDEX of Component
const mapStateToProps = state => ({
(...cutting out a bunch of state here)
collectionBeingEdited: state.research.collectionBeingEdited,
removeReport: state.research.removeReport,
userInfo: state.account.myAccount.info,
})
//IN COMPONENT
console.log(this.props)
//result -> removeReport: undefined
InitialState of a reducer is not a reducer. As Martin suggested, you need to post your actual reducer.
I'm willing to bet that in one of your reducer cases its not returning the rest of the state:
case 'something':
return {
someKey: action.value
}
instead of:
case 'something':
return {
...state,
someKey: action.value
}
and thats why the property you're expecting doesnt exist.
Can anyone help with this update pattern. I am not using any libraries like immer.
I have to update a nested object and the data looks like dis
Sample data
{
isFetching: false
data:{
nba : {
stack :{
1:[]
}
}
}
}
My Reducer
{
...state,
isFetching: false,
data: {
...state.data,
[action.payload.team]: {
...state[action.payload.team],
[action.payload.framework]: {
...state[action.payload.framework],
[action.payload.build]: action.payload.resp
}
}
}
};
I am able to update until second level but unable to update third child.
can anyone throw a light on where i am missing it.
I put a demo on codesandbox.
https://codesandbox.io/s/todos-0ygrs
Click on collapse and inner collapse items. I am logging the changes for the state in the console below. As you can see at last level, build numbers are getting replaced with the new one's.
Current Behaviour After you expand nba and all the three childs
{
nba: {
stack:{
3:[]
}
}
Expected Behaviour: After you expand stack and all the three childs
{
nba: {
stack:{
1:[],
2:[],
3:[]
}
}
}
You probably have to use a get helper because you may try to set a part of state that doesn't exist yet.
With the get helper you can set the state like this:
const { team, framework, build, resp } = action.payload;
const newState = {
...state,
isFetching: false,
data: {
...get(state, ['data']),
[team]: {
...get(state, ['data', team]),
[framework]: {
...get(state, ['data', team, framework]),
[build]: resp,
},
},
},
};
Somehow i figured out my mistake, Hope it helps someone in future
Initial state should not be null, it should be empty object and update pattern should be in this manner
{
...state,
isFetching: false,
data: {
...state.data,
[action.payload.team]: {
...state.data[action.payload.team],
[action.payload.framework]: {
...state.data[action.payload.team][action.payload.framework],
[action.payload.build]: action.payload.resp
}
}
}
};
if it fails, then try this way
let teamTemp = { ...state.data[action.payload.team]}
{
...state,
isFetching: false,
data: {
...state.data,
[action.payload.team]: {
...teamTemp ,
[action.payload.framework]: {
...teamTemp[action.payload.framework],
[action.payload.build]: action.payload.resp
}
}
}
};
I have forked my codesandbox and updated latest code.
Old Code: https://codesandbox.io/s/todos-0ygrs
New Code: https://codesandbox.io/s/todos-zqeki
I have the following code in my reducer. It works fine except that when comment.parentPostId is null. I wonder how I can run [comment.parentPostId] part only when comment.parentPostId is not null.
As a solution, I can define two reducers, one per each condition. But, it does not seem like a solid approach. Any suggestions?
case POST_COMMENT_SUCCESS:
const comment = action.payload.normalizedData;
return {
...state,
loading: false,
editing: false,
alignPerspectives: {
...state.alignPerspectives,
[comment.submissionId]: {
...state.alignPerspectives[comment.submissionId],
discussionPosts: [...state.alignPerspectives[comment.submissionId].discussionPosts, comment.id]
}
},
discussionPosts: {
...state.discussionPosts,
[comment.id]: comment,
[comment.parentPostId]: {
...state.discussionPosts[comment.parentPostId],
childPosts: [...state.discussionPosts[comment.parentPostId].childPosts, comment.id]
}
}
};
You can always split your reducer and delgate some part of the process to the other reducer as mentioned here https://redux.js.org/recipes/structuring-reducers/splitting-reducer-logic
OR
You can use a ternary operator to check if it's a valid value and return the state object accordingly
case POST_COMMENT_SUCCESS:
const comment = action.payload.normalizedData;
return comment.parentPostId ? {
...state,
loading: false,
editing: false,
alignPerspectives: {
...state.alignPerspectives,
[comment.submissionId]: {
...state.alignPerspectives[comment.submissionId],
discussionPosts: [...state.alignPerspectives[comment.submissionId].discussionPosts, comment.id]
}
},
discussionPosts: {
...state.discussionPosts,
[comment.id]: comment,
[comment.parentPostId]: {
...state.discussionPosts[comment.parentPostId],
childPosts: [...state.discussionPosts[comment.parentPostId].childPosts, comment.id]
}
}
} : {
...state,
loading: false,
editing: false,
alignPerspectives: {
...state.alignPerspectives,
[comment.submissionId]: {
...state.alignPerspectives[comment.submissionId],
discussionPosts: [...state.alignPerspectives[comment.submissionId].discussionPosts, comment.id]
}
},
discussionPosts: {
...state.discussionPosts,
[comment.id]: comment,
}
}
Hope this helps !