unable to understand reducer function in react redux - reactjs

this is my reducer function :
export default (posts = [], action) => {
switch (action.type) {
case FETCH_ALL:
return action.payload;
case LIKE:
return posts.map((post) => (post._id === action.payload._id ? action.payload : post));
case CREATE:
return [...posts, action.payload];
case UPDATE:
return posts.map((post) => (post._id === action.payload._id ? action.payload : post));
case DELETE:
return posts.filter((post) => post._id !== action.payload);
default:
return posts;
}
};
in
case CREATE:
return [...posts, action.payload];
what i have understood so far is that reducer function gets old state and new state . old state is represented by 'posts' and new state is represented by 'action.payload' ...now what i do not understand is that what is [...posts, action.payload] ?
what are those three dots ?
why there are square brackets ?
what does reducer function returns ?
what is happening here ?
i am a java programmer , i can't understand anything here

i have understood everything .
reducer function is getting two parameters (posts = [], action) :
first one is old state and the second parameter is action object which includes type and new data ...this reducer function returns a new state by adding my new data into old state
in this
case CREATE:
return [...posts, action.payload];
these ...three dots are spread syntax which can be understood completely by going to the following link given by chellappan in comment section :
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
[]square brackets denote an array which is our new state.

Related

How to update the state of an object in react-redux

My question might sound stupid but I swear my brain freeze, I google it for answer but honestly I don't even know what should I search for. So basically I have a reducer, usually when I'm using redux I'm using arrays and my reducers look like this:
import { FETCH_ALL, CREATE, UPDATE, DELETE } from '../constants/actionTypes';
export default (posts = [], action) => {
switch (action.type) {
case FETCH_ALL:
return action.payload;
case CREATE:
return [...posts, action.payload];
case UPDATE:
return posts.map((post) => post._id === action.payload._id ? action.payload : post);
case DELETE:
return posts.filter((post) => post._id !== action.payload);
default:
return posts;
}
};
And now I only have an object, and I really don't know what to write on case UPDATE, I mean I'm not looping through and find my updated object and that process.
My question is how can I update if I only have an object
import { FETCH_PROFILE, UPDATE_PROFILE } from '../constants';
export default (profile= {}, action) => {
switch (action.type) {
case FETCH_PROFILE:
return action.payload;
case UPDATE_PROFILE:
return ;
default:
return profile;
}
};
like here, in that case UPDATE_PROFILE, what should I write to make it work, in my backend everything going well, the return is an object with the updated user.
I know my question is stupid, but please be kind! Thank you in advance
Unexpected token, expected "," (8:32)
6 | return action.payload;
7 | case UPDATE_PROFILE:
> 8 | return {...profile, action.payload};
| ^
9 | default:
10 | return profile;
11 | }
For object you will use spread operator just like in an array:
import { FETCH_PROFILE, UPDATE_PROFILE } from '../constants';
export default (profile= {}, action) => {
switch (action.type) {
case FETCH_PROFILE:
return action.payload;
case UPDATE_PROFILE:
return {...profile, action.payload};
default:
return profile;
}
};
More about it here.
In your update profile, pass the entire object after updating.
For eg:
let profiles =[{name:"foo",id:1},{name:"bar",id:2},{name:"baz",id:3}]
let updateProfile = [{id:2,name:"gaurav"}]
then, first update the profiles with updated profile, that is,
const updatedProfiles = profiles.map(item=>item.id===?:updatedProfile:item)
then, simply pass updatedProfiles in action.payload,
in your reducer, it will be then
case UPDATE_PROFILE:
return action.payload;

Updating State for changed item not displaying on react frontend

I am working on my reducer and I am trying to get the case for UPDATE working.
I am just trying to update the list on my react frontend when a certain object ID changes in the state. How can I make it so the item with a certain ID changes on the frontend in this reducer.
I tried this in UPDATE_ANIMALS, but no luck
case 'UPDATE_ANIMALS':
return [
...state, item => item.id === action.payload.id ? action.payload : item
];
Below is my entire reducer.
export const ANIMALSReducer = (state = [], action) => {
switch (action.type) {
case 'FETCH_ANIMALS':
return action.payload;
case 'ADD_ANIMALS':
return [...state, action.payload];
case 'DELETE_ANIMALS':
return [
...state.filter(item => item.id !== action.payload)
];
case 'UPDATE_ANIMALS':
return [
NOT SURE WHAT TO PUT HERE
];
default:
return state;
}
};
You can achieve that very easily using the map function, basically you're generating a new array and the matching item given your payload will be updated with the payload instead the original:
case 'UPDATE_ANIMALS':
return state.map(item => item.id === action.payload.id ? action.payload : item);

Redux reducer isn't returning the updated state to UI

I have a reducer case, and this case is supposed to add a comment, and update the UI with the new comment,
Pretty much you add a comment, and it will show under the rest of comments once you do, the logic is not returning the new state for some reason.
What could be the cause of this ? And to be honest im unsure of what im doing, im fairly new when it comes to reducer normalizer state updates.
Only on refresh i see the new comment.
const initialState = {
allIds:[],
byId:{},
};
const allIds = (state = initialState.allIds, action) => {
switch (action.type) {
case FETCH_IMAGES_SUCCESS:
return action.images.reduce((nextState, image) => {
if (nextState.indexOf(image.id) === -1) {
nextState.push(image.id);
}
return nextState;
}, [...state]);
case UPLOAD_IMAGE_SUCCESS:
console.log(action.data)
return [action.data.id, ...state];
case POST_COMMENT_SUCCESS:
console.log(action)
return [action.data.id, ...state];
default:
return state;
}
}
const image = (state = {}, action) => {
switch (action.type) {
case POST_COMMENT_SUCCESS:
return [...state.comments, action.data, ...state.comments]
default:
return state;
}
}
const byId = (state = initialState.byId, action) => {
switch (action.type) {
case FETCH_IMAGES_SUCCESS:
return action.images.reduce((nextState, image) => {
nextState[image.id] = image;
return nextState;
}, {...state});
case POST_COMMENT_SUCCESS:
console.log(action.data) // renders new commnent
return {
...state,
...state.comments,
[action.data.id]: action.data,
}
case UPLOAD_IMAGE_SUCCESS:
console.log(action)
return {
...state,
[action.data.id]: action.data,
};
default:
return state;
}
}
Not sure because I don't see the shape of your byId object, but I think the problem might be here:
case POST_COMMENT_SUCCESS:
return {
...state, // here you are spreading the whole state object
// and here you are spreading state.comments at the same level, NOT nested:
...state.comments,
// Again same thing here, not nested:
[action.data.id]: action.data,
}
Instead you should be doing something like this, more info in the Redux docs:
case POST_COMMENT_SUCCESS:
return {
...state,
comments: {
...state.comments,
[action.data.id]: action.data
}
}
Alternatively, you could use Immer to simplify your reducers, I'm using it and I'm loving it. It feels a little bit weird because you can use mutation methods to modify its draft but it is great if you want to have simpler reducers. Your code with Immer would be something much more simpler:
case POST_COMMENT_SUCCESS:
draft.comments[action.data.id]: action.data,
return;
With Immer you just have to modifiy (or mutate) the draft object, if the value you are assigning to is different from the one you have in state, it will generate a new object for you, otherwise it will return state.
Hope it helps.

How to update 1 item in state with redux?

I have a reducer and trying to update 1 item in the statearray. It looks like this:
const players = (state = [{name:'John',nrGames:0,nrWins:0},{name:'Ed',nrGames:0,nrWins:0},{name:'Mark',nrGames:0,nrWins:0}], action) => {
switch (action.type) {
case 'ADD_PLAYER':
return [...state,{name:action.name}]
case 'ADD_WIN':
return [...state, action.name == 'bla' ? {nrWins:10} : {} ]
default:
return state;
}
};
export default players;
I am trying to figure out how to change the nrWins property for a certain name. So when ADD_WIN is dispatched with name='John' how to just update the John object and up the nrWins property with 1 and not the other objects in the state?
You need to .map over the players and when you find the one the action is describing create a new player with the updated number of wins. For readability I created a function called incWinForPlayer.
const incWinForPlayer = (name) => (player) => {
return player.name === name
? {...player, nrWins: player.nrWins + 1}
: player
};
const players = (state, action) => {
switch (action.type) {
case 'ADD_PLAYER':
return [...state, {name: action.name}]
case 'ADD_WIN':
return state.map(incWinForPlayer(action.name));
default:
return state;
}
};
export default players;
The "recommended" approach is to slice the old array up to the new item, concat it with the modified one, and concat it with the rest of the array.
Make sure that your action returns the whole new item, and the index you want to modify.
Something like:
case 'ADD_WIN':
return [
...array.slice(0, action.index),
action.item,
...array.slice(action.index)
];
Edit 1: source https://redux.js.org/docs/recipes/reducers/ImmutableUpdatePatterns.html#inserting-and-removing-items-in-arrays

Redux shopping cart example

I'am trying to understand the example named "shopping cart" giving for redux :
https://github.com/reactjs/redux/tree/master/examples/shopping-cart
In this example you can add elements to your list of items, I tried to implement the function of remove a list of items :
But in the reducers folder there is an addedIds() function, I added a case to remove the element of the list but I don't know how to implement that, here is the function : the reste of my code is working fine I just don't know how to delete the product id from the array of addedIds.
const initialState = {
addedIds: [],
quantityById: {}
};
function addedIds(state = initialState.addedIds, action) {
switch (action.type) {
case ADD_TO_CART:
console.log("added ADD");
if (state.indexOf(action.productId) !== -1) {
return state
}
return [ ...state, action.productId ];
case REMOVE_TO_CART:
console.log("removed ADD");
// here is my problem
default:
return state
}
}
I assumed I need to do something like here :
Is this the correct way to delete an item using redux?
but I don't know how
Can you help me please ?
You can delete some element from array just filtering it out:
// ... skipped other cases from the switch
case REMOVE_TO_CART:
return state.filter(productId => action.productId !=== productId)
Approach with .filter() function looks very short and produces a new array instance as it required by redux.
For those who have a similar problem here is the solution :
const initialState = {
addedIds: [],
quantityById: {}
};
function addedIds(state = initialState.addedIds, action) {
switch (action.type) {
case ADD_TO_CART:
console.log("added ADD");
if (state.indexOf(action.productId) !== -1) {
return state
}
return [ ...state, action.productId ];
case REMOVE_TO_CART:
console.log("removed ADD");
return [ ...state.slice(0,state.indexOf(action.productId),
...state.slice(state.indexOf(action.productId)+1))
];
default:
return state
}
}
thanks to Josh Deeden who found this vidéo :
https://egghead.io/lessons/javascript-redux-avoiding-array-mutations-with-concat-slice-and-spread

Resources