Here is the State object:
const initialState = {
data: {
user: '',
token: '',
}
}
Reducer:
case 'DO_SOMETHING':
return {...state, data: action.payload }
If I soft copy the state as shown above, I will overwrite the entire data part of the state. How can I update only the user with the given payload without overwriting the token?
If the payload is just the user, then simply use the same destructuring pattern you used for the state object in general:
return {
...state,
data: {
...state.data,
user: action.payload
}
}
This pattern can be nested as much as you like, so you can have large structured state objects and just pass around the fields you want in the payloads.
Try this, (considering action.payload is the entire data object)
case 'DO_SOMETHING':
return {...state, data: { ...state.data, user: action.payload.user } }
Spread the nested object too:
return {...state, data: {...state.data, user: action.payload} }
Related
I want to know what does ...state inside { ...state } do? Is it to change the value of the store to the initial value or to let the store be the latest value?
import * as actionType from "../actions/actionTypes";
const initialStore = {
roomsCount: 0,
resPerPage: 0,
rooms: [],
filteredRooms: 0,
error: null,
success: false,
};
const reducer = (state = initialStore, action) => {
switch (action.type) {
case actionType.ALL_ROOM_SUCCESS:
return {
...state,
success: true,
rooms: action.rooms,
roomsCount: action.roomsCount,
resPerPage: action.resPerPage,
filteredRooms: action.filteredRooms,
};
case actionType.ALL_ROOM_FAILED:
return {
...state,
error: action.err,
};
}
};
If at first I use this reducer, it'll be successful so success will be true and error will be null. But if it fails the 2nd time and I use ...state in this situation, what is the success value? Is it the initial value (false) or does it keep the value from the first request (true)?
That is called the spread operator and it basically allows you to "clone" the fields of one object into a new object.
In your example, { ...state, error: action.err } means "copy all fields from state, but set the field error to action.err". It's very handy for this kind of logic where you want to change a very few fields but otherwise want to keep the original data.
Learning React with Redux, the course author wrote this:
export default (state = [], action) => {
switch (action.type) {
case FETCH_STREAM:
return { ...stream, [action.payload.id]: action.payload };
case CREATE_STREAM:
return { ...stream, [action.payload.id]: action.payload };
case EDIT_STREAM:
return { ...stream, [action.payload.id]: action.payload };
default:
return state;
}
};
As much as I understood, the { ...stream, [action.payload.id]: action.payload } pattern is a new JavaScript syntax called "Key Interpolation Syntax" and what it does is that it adds a new key/value to our object ( which we have made a copy of it with spread ... syntax first ) so in that case I do understand the CREATE_STREAM one, but how about EDIT_STREAM ? Is it gonna replace the key because the key is already in there? or is it gonna blindly add it so then duplicate key? Also I don't understand the FETCH_STREAM at all. Why is it even like this? Shouldn't it just be a return action.payload ?
Actually, the Key Interpolation syntax will add that key if it doesn't exist but will override its value if it is duplicated.
The following code
const personA = {
name: 'John Doe',
age: 42
};
const createdProp = 'country';
const overriddenProp = 'age';
const personB = {
...personA,
[createdProp]: 'USA',
[overriddenProp]: 50
};
Will result in personB with these values
{
name: "John Doe",
age: 50,
country: "USA"
}
About the FETCH it depends on what they intended. If the spread operation is removed, then all previous data will be lost. If that is no problem, you can do { [action.payload.id]: action.payload } without worries.
I want to add a post to an array of posts in the reducer.
Normally I would just do this:
CREATE_NEW__POST_SUCCESS: {
return {
...state,
fetchingPosts: false,
error: null,
posts: [...state.posts, ...action.payload],
};
However my current project requires me to use Immutable.js
With Immutable the state is set with .set() or .merge() or .update()
case CREATE_NEW_POST_SUCCESS: {
return state
.set('fetchingPosts', false)
.set('posts', action.payload)
.set('postsError', null);
This overwrites the whole array of posts with just one post object.
I tried lots of things like
.set('posts' ,[...state.posts, ...action.payload])
But no joy
You can use updateIn similarly to the answer here.
case CREATE_NEW_POST_SUCCESS: {
return state
.set('fetchingPosts', false)
.updateIn(['posts'], posts => posts.push(action.payload))
.set('postsError', null);
I think state.merge() and concat() could work here:
case CREATE_NEW_POST_SUCCESS: {
return state.merge({
fetchingPosts: false,
posts: state.get('posts').concat(action.payload),
postError: null,
})
}
I am trying to fetch a new batch of products through an action and then replace the state with the new batch, however it just adds it to the array...
Here's my reducer for controlling the state:
const initialState = {
fetching: false,
fetched: false,
Brands:[],
Markings:[],
Products: [],
error: null
}
export default function reducer(state=initialState, action=null) {
switch (action.type){
case "FETCH_PRODUCTS_PENDING" : {
return {...state}
break;
}
case "FETCH_PRODUCTS_REJECTED" : {
return {...state}
break;
}
case "FETCH_PRODUCTS_FULFILLED" : {
return{ ...state,
Products: state.Products.concat(action.payload.data.Products),
Brands: action.payload.data.Facets[0].Facets,
Markings: action.payload.data.Facets[1].Facets
}
break;
}
}
return state
}
It goes wrong in the fulfilled case.. I am not sure how this "...state" works, do I need to do a object assign or something?
Upon load I get 52 products, when trying to request a new batch it adds it up so my this.props.products is 104 items... I want it to replace
This line is the culprit
Products: state.Products.concat(action.payload.data.Products),
In this case all you want to do is replace the Products array with the one from the action.
So it should be simply
Products: action.payload.data.Products
See here for a nice explanation on the spread operator:
https://ponyfoo.com/articles/es6-spread-and-butter-in-depth
Below is my code
function customMsg(state, action) {
state = state || {
person: {
isFetching: false,
didInvalidate: false,
name: "",
height: "",
}
};
switch(action.type) {
case ACTION_TYPES.PERSON.FETCH_PERSOn_CONTENT_SUCCESS:
return $.extend({}, state, {
person.name: action.result.name
});
default:
return state;
}
}
How do I only update one value of my reducer in Redux?
Above is a example which i only want to update the name of person object.
How can i do that?
Using jQuery extend, create a clone and set person name:
var newState = $.extend({}, state);
newState.person.name = action.result.name;
return newState;
Otherwise, to clone deeply an object you can use lodash cloneDeep().
Another way is to use immutableJS to set your app state as immutable. It is much more bug "mutable" proof and offers functions to set deep nested value in an immutable. See updateIn:
return state.updateIn(['person', 'name'], () => action.result.name);
Try it!