Reputation: 266910
So I have an action that is fetching from an API.
I am fetching the user from my API, and it returns the JSON with and returns with the action and the json values for the user and a progress value.
fetchUser: (userId) => {
return dispatch => {
dispatch({ type: Constants.USER_FETCHING });
let url = 'http://localhost:4001/api/v1/users/'+ userId;
axios.get(url)
.then(function(data) {
console.log('data returned is ' + JSON.stringify(data));
dispatch({
type: Constants.GET_USER,
user: data.user,
progress: data.progress,
});
});
};
},
Now in my reducer I have to return the state without mutating it:
import Constants from '../constants';
const initialState = {
users: [],
user: null,
progress: null,
fetching: false,
};
const users = (state = initialState, action) => {
case Constants.USER_FETCHING:
return {...state, fetching: true};
switch (action.type) {
case Constants.GET_USER:
return ?????;
default:
return state;
}
};
export default users;
How exactly should I be returning the state?
I see examples using Object.assign but not sure how to structure it for my case:
return Object.assign({}, state, ????);
Upvotes: 0
Views: 58
Reputation: 1522
Both Karbaman and Tony answers are correct. Furthermore, the Object spread is compiled to Object.assign
by default if you're using babel
, as you can read in the documentation.
To add to those answers, if you want to update the users
array, you can use the spread transform (documentation):
case Constants.GET_USER:
return {
...state,
user: action.user,
progress: action.progress,
users: [ ...state.users, action.user ]
};
Which will create a new array for users, concat
it with the existing one, then with the new user
.
However, if the user
in the action
is already within the existing array, it will get duplicated. You can implement a verification to avoid that, or use directly union from lodash
(if user
is a String
or Number
):
....
users: union(state.users, [action.user])
...
Upvotes: 1
Reputation: 6482
You can use the spread operator ...
as you did in your USER_FETCHING
:
case Constants.GET_USER:
return {
...state,
user: action.user,
progress: action.progress
};
This creates a new object by first setting the same properties as they currently are on state
, and then overwrites the user
and progress
properties with the new values from the action
.
Upvotes: 2
Reputation: 3182
If you are going to use Object.assign, then it will be:
return Object.assign({}, state, {user: action.user, progress: action.progress});
How it works: Object.assign gets 3 objects:
and merges them into 1 object one by one.
It is important to have empty object ( {} ) as a first argument, because in this case props/values from state will be merged to empty object and you will have a new copy. If you remove empty object or put state as a first argument - in this case everything will be merged to state and you will have a mutation instead of copying.
Upvotes: 1