Need to append data in the array in reducer of redux - javascript

I am doing pagination where i will be getting data for each page click.I want to append the data with the previous values.Here is my current code.Have no idea to do it.
const InitialProjects={
projectList:[],
error:null,
loading:false
}
export const projects=(state=InitialProjects,action)=>{
switch(action.type){
case ActionTypes.FETCH_PROJECTS:
return Object.assign({},state,{
projectList:[],error:null,loading:true
})
case ActionTypes.FETCH_PROJECTS_SUCCESS:
return {
projectList:action.payload
}
case ActionTypes.FETCH_PROJECTS_FAILURE:
return Object.assign({},state,{
projectList:["not-found"],error:action.payload.message||action.payload.status,loading:false
})
default:
return state;
}
}
My first response will look something like this
[
{
Id:0,
Name:india
},
{
Id:1,
Name:bang
},
{
Id:3,
Name:us
},
{
Id:5,
Name:uk
}
]
second response will be like this
[
{
Id:8,
Name:india
},
{
Id:12,
Name:bang
},
{
Id:19,
Name:us
},
{
Id:35,
Name:uk
}
]
Please do note that the id field might not be consecutive.
I want something like this in my redux
projectList:
0(pin): {Id:1,Name:'dewd'}
1(pin): {Id:2,Name:'tyytg'}
2(pin): {Id:5,Name:'xsx'}
3(pin): {Id:4,Name:'tyyt'}
4(pin): {Id:10,Name:'xsx'}
5(pin): {Id:17,Name:'xsx'}
Appreciate any help.Thanks

You can spread the results on each success.
case ActionTypes.FETCH_PROJECTS:
return {
...state,
error: null,
loading: true,
}
case ActionTypes.FETCH_PROJECTS_SUCCESS:
return {
...state,
projectList: [...state.projectList, ...action.payload]
}

Looks like the object spread operator doesn't work in your case. So an ES5 version of the answer for you would be.
case ActionTypes.FETCH_PROJECTS_SUCCESS:
return Object.assign(
{},
state,
{
projectList: state.projectList.concat(action.payload)
});
This copies all the previous values from state into a new object by using Object.assign then overwrites a new projectList property by concatenating old values from state.projectList and new ones from action.payload.
Hope it helps!

Related

Cant change boolean value in object (React)

This is my state object. I am trying to change "isVisible" value from "HideUser" case that i provided below. But output is allways gives me same isVisible value. And i cant flip it. I would appreciate for any help.
Note: when i say isVisible=false, it works. And isVisible value is allways same when i print.
state={
users:[
{
id:1,
isim:"Muhammedcan Pirinççi",
okul:"Marmara",
maaş:"a4000",
isVisible:true
},
{
id:2,
isim:"Suat Pirinççi",
okul:"Marmara",
maaş:"a10000",
isVisible:true
}
],
dispatch: action => {
this.setState(state=>reducer(state,action))
}
}
HideUser case:
case "HIDE_USER":
return{
...state,
users: state.users.map(user => {
if (user.id===action.payload) {
user.isVisible=!user.isVisible
return user
}
else{
return user
}
})
}

rest operator to omit properties

I'm attempting to use the rest operator and restructuring to omit an entry in the object. Based on the documentation, rest should no longer include the key entry 575. After the operation, rest still has the same keys as state. I'm not sure what I'm doing wrong. Thanks in advance.
book = {
id: 575,
title: "Vector Calc"
};
state = {
removedBooks: {
46: {
id: 46,
title: "economics"
},
575: {
id: 575,
title: "Vector Calc"
}
}
};
const {
[book.id]: data, ...rest
} = state;
console.log(rest);
EDIT: I am using React and it is not recommended to mutate the state object directly. Why can't I directly modify a component's state, really? among others
The books are part of the removedBooks property, and are not direct children of the state. You need to destructure the removedBooks property as well.
const book = {"id":575,"title":"Vector Calc"};
const state = {"removedBooks":{"46":{"id":46,"title":"economics"},"575":{"id":575,"title":"Vector Calc"}}};
const { removedBooks: { [book.id]: data, ...removedBooks } } = state;
const newState = { ...state, removedBooks };
console.log(newState);
Your destructuring assignment expects a pattern of { 575: data, ...other... } but state actually has { removedBooks: { 575: data, ...other... } }. Add the removedBooks into your destructuring assignment and it works fine.
book = {
id: 575,
title: "Vector Calc"
};
state = {
removedBooks: {
46: {
id: 46,
title: "economics"
},
575: {
id: 575,
title: "Vector Calc"
}
}
};
const { removedBooks: {
[book.id]: data, ...rest
} } = state;
console.log(rest);

How do I properly update an item in my array in redux without mutating?

const state = [
{
list: []
}
];
The list is a list of student objects, for example:
list: [
{ id: 1, name: "Mark", attendance: true },
{ id: 2, name: "John", attendance: false }
]
I have a button that triggers a post request to an API to change attendance to true. Post request returns the student object that was changed as in e.g.:
{ id: 2, name: "John", attendance: true }
This works fine and if no errors, will dispatch ATTENDANCE_SUCCESS.
Now, with this kind of set-up:
export function students(state, action) {
let latestState = state[state.length - 1],
newState = Object.assign({}, latestState);
switch (action.type) {
case "ATTENDANCE_SUCCESS":
if (action.res.errorCode == 0) {
// Need to change redux state 'attendance' value to true for a student with ID returned from the POST request
}
}
Initially, I did:
const studentChanged = newState.list.find(function(student) {
return (
student.id ===
action.res.data.id
);
});
studentChanged.attendance = true;
But it mutates the state in the redux store (although I am not sure how it's exactly happening since I assumed newState is already a copy).
What's the proper way?
The following would update a single item in the array. The critical aspect here is that if the id of the item does not match the id from the action payload, it returns the item unaltered, otherwise it updates the attendance property. Array.prototype.map returns a new array so it would be immutable.
export function students(state, action) {
switch (action.type) {
case "ATTENDANCE_SUCCESS":
if (action.res.errorCode == 0) {
return state.map(student => {
// we want to leave non matching items unaltered
if (student.id !== action.res.data.id) {
return student;
}
return { ...student, attendance: true };
});
}
return state;
default:
return state;
}
}
Here is a StackBlitz to demonstrate the functionality.
Hopefully that helps!

Redux action creator syntax

function addTodoWithDispatch(text) {
const action = {
type: ADD_TODO,
text
}
dispatch(action)
}
http://redux.js.org/docs/basics/Actions.html#action-creators
I saw the code above from redux documentation. What I don't understand is the text in the action. It doesn't look like a valid javascript object or array syntax. Is it an ES6 new syntax? Thanks.
It is just a new ES6 syntax, which simplifies creating properties on the literal syntax
In short, if the name is the same as the property, you only have to write it once
So this would be exactly the same :)
function addTodoWithDispatch(text) {
const action = {
type: ADD_TODO,
text: text
}
dispatch(action)
}
In the above code
function addTodoWithDispatch(text) {
const action = {
type: ADD_TODO,
text
}
dispatch(action)
}
here text is an example of object literal shorthand notation. ES6 gives you a shortcut for defining properties on an object whose value is equal to another variable with the same key.
As has been said this is just shorthand for writing
const action = {
type: ADD_TODO,
text: text
}
dispatch(action)
Have a look at this blog
If you look at the next page in document http://redux.js.org/docs/basics/Reducers.html
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
})
case ADD_TODO:
return Object.assign({}, state, {
todos: [
...state.todos,
{
text: action.text,
completed: false
}
]
})
case TOGGLE_TODO:
return Object.assign({}, state, {
todos: state.todos.map((todo, index) => {
if(index === action.index) {
return Object.assign({}, todo, {
completed: !todo.completed
})
}
return todo
})
})
default:
return state
}
}
It is expecting property name text. As #Icepickle mentioned it is a valid format but you can also change to below format:
function addTodoWithDispatch(text) {
const action = {
type: ADD_TODO,
text:text
}
dispatch(action)
}

Changing a nested array value based on a given index in a reducer while not mutating state

I have a reducer working with an object with arrays. I want to change a value on the nested arrays based on a given index. This code works but I can't seem to get my test to work using deep freeze. I was trying to look at the redux example here http://redux.js.org/docs/basics/Reducers.html using .map to find the index with no luck. Any ideas?
export default function myReducer(state = { toDisplay: [] }, action) {
const { type, groupIndex, itemIndex } = action;
const newObject = Object.assign({}, state);
switch (type) {
case actionTypes.TOGGLE_GROUP:
newObject.toDisplay[groupIndex].isSelected = newObject.toDisplay[groupIndex].isSelected ? false : 'selected';
return newObject;
case actionTypes.TOGGLE_ITEM:
newObject.toDisplay[groupIndex].values[itemIndex].isSelected = newObject.toDisplay[groupIndex].values[itemIndex].isSelected ? false : true;
return newObject;
default:
return state;
}
}
EDIT:
For anyone curious after watching a helpful redux video I came up with this:
export default function myReducer(state = { toDisplay: [] }, action) {
const { type, groupIndex, itemIndex } = action;
switch (type) {
case actionTypes.TOGGLE_GROUP:
return {
...state,
toDisplay: [
...state.toDisplay.slice(0, groupIndex),
{
...state.toDisplay[groupIndex],
isSelected: state.toDisplay[groupIndex].isSelected ? false : 'selected'
},
...state.toDisplay.slice(groupIndex + 1)
]
};
case actionTypes.TOGGLE_ITEM:
return {
...state,
toDisplay: [
...state.toDisplay.slice(0, groupIndex),
{
...state.toDisplay[groupIndex],
values: [
...state.toDisplay[groupIndex].values.slice(0, itemIndex),
{
...state.toDisplay[groupIndex].values[itemIndex],
isSelected: state.toDisplay[groupIndex].values[itemIndex].isSelected ? false : true
},
...state.toDisplay[groupIndex].values.slice(itemIndex + 1)
]
},
...state.toDisplay.slice(groupIndex + 1)
]
};
default:
return state;
}
}
Using a helper/library like suggested is probably the best route but my team wishes to not add another dependency.
Firstly, Object.assign(...) only does a shallow copy. See here.
As you have objects nested inside arrays nested inside objects I would highly recommend the immutability helpers from react (as mentioned by Rafael). These allow you to do something like this:
case actionTypes.TOGGLE_GROUP:
return update(state, {
toDisplay: {
[groupIndex]: {
isSelected: {$set: newObject.toDisplay[groupIndex].isSelected ? false : 'selected'}
}
}
});
If you are looking to modify a simple value inside an array with raw js then you can use something like this:
return list
.slice(0,index)
.concat([list[index] + 1])
.concat(list.slice(index + 1));
(source)

Categories

Resources