how to update a specific value in an object in redux - reactjs

My Reducer :
function updatePersonDetailsReducer (state = {
updatePersonDetails: {
name: "John",
id: "3ery4",
address: "somewhere on earth"
}
}, action) {
switch (action.type) {
case C.UPDATE_PERSON_DETAILS: {
return {
...state
,updatePersonDetails :action.payload
}
}
default : {}
}
return state
}
I called this way in my component,
this.props.dispatch(updatePersonDetails({name:Variant.objValue.name,id:Variant.objValue.Id}))
But this seems to, create a new array than overwriting the values in the current array (updatePersonDetails) in reducer.

You can spread your object and do it like this.
case C.UPDATE_PERSON_DETAILS: {
return {
...state,
updatePersonDetails :
{...state.updatePersonDetails,...action.payload}
}
}
This will keep your old keys there and will only update the newly added keys.

Related

Why the new value is not dispatched?

I am trying to set new values by redux but a single key "status" every time after dispatching as an empty string. I don't know what is it and why every time empty maybe somebody know solution?
call action and dispatch code:
store.dispatch(actionSetNewResponseFilterValues({
active_level: "1",
query_in: ["0"],
status: ["15"]})
);
action method:
export const actionSetNewResponseFilterValues = (newValues) => {
return {
type: SET_RESP_FILT_VALS,
newValues
}
}
and code in reducer:
case SET_RESP_FILT_VALS:
case LOAD_RESP_FILT_VALS:
return {
...state,
filter: {
...state.filter,
newValues: {
...state.filter.newValues,
...action.newValues
}
}
}
#udpated
when in reducer coding whithout destructuring-assignment:
case SET_RESP_FILT_VALS:
case LOAD_RESP_FILT_VALS:
return {
...state,
filter: {
...state.filter,
newValues: action.newValues
}
}
in dispatching I see an empty status key:

React: context hook, push object into an array

The error I'm getting is Cannot find name 'objectArray'.
interface StateInterface {
objects: {
objectArray: object[];
selected: object;
};
}
const InitialState: StateInterface = {
objects: {
objectArray: [],
selected: {},
},
};
const Reducer = (state: StateInterface, action: any) => {
switch (action.type) {
case 'SELECTED':
return {
...state,
objects: { ...state.objects, selected: action.value },
};
case 'ADD_OBJECT':
return {
...state,
objects: { ...state.objects, objectArray: objectArray.push(action.value )},
// ^---- Cannot find name 'objectArray'.ts(2304)
};
default:
return state;
}
};
I also tried
objects: { ...state.objects, objectArray: ...action.value )},
Only the state object is in scope at that point (provided as an argument to the reducer), try switching objectArray for state.objectArray at the point you're getting the error.
But also, you'll need to append the value immutably for it to be correct (a rule of reducers), so you'll need to make that whole line something like:
objects: { ...state.objects, objectArray: [...state.objectArray, action.value]},
To create a new array with both the old values and the new value you're adding.

Composing a redux reducer for nested objects in an array

I'm new to Redux and am having some difficulty composing a working reducer for my situation.
My current state looks like this
export const userData = {
userID: '12345678',
userDetails: {
firstName: 'Joe',
surname: 'Bloggs'
},
currentGames: [
{
gameId: 'G-00000001',
gameSelections: [
{
subgameId: '',
selection: ''
}
]
}
]
};
My action looks like this
function selectWinner (gameId, subgameId, selection) {
return {
type: SELECT_WINNER,
gameId,
subgameId,
selection
}
}
The aim is to be able to add/update the objects in the gameSelections array.
There may be more than one Object in the currentGames array also.
I've heard I should use .map but I'm not really sure how.
You're on the right track for using .map() to iterate over the array of objects. It also looks like your action-creator has all the necessary parameters to update your reducer state.
Your reducer can look something like this:
const userReducer = (state=userData, action) => {
switch(action.type){
case SELECT_WINNER:
return {
...state,
currentGames: [...state.currentGames].map((game) => {
if(game.gameId == action.gameId){
return {
...game,
gameSelections: [...game.gameSelections].map((gameSelection) => {
if(gameSelection.subgameId == action.subgameId){
return {
...gameSelection,
selection: action.selection
}
} else {
return gameSelection
}
})
}
} else {
return game
}
})
}
default:
return state
}
}
Kind of messy, but would get the job-done with a deeply nested state.
Add item to array:
case'ADD_ITEM':
return {
...state,
some_arr: [...state.some_arr, action.payload]
}
update spicific item in array:
case 'UPDATE_ITEM':
return {
...state,
some_arr: state. some_arr.map(
(item, index) => index === specific_index
? {...item, ...action.payload}
: content
)
}
Deep cloning of the state is required.
useful link-https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns
const reducer = (state = userData, action) => {
switch (action.type) {
case CASENAME:
return {
userID: state.userID,
userDetails: {
...state.userdetails
},
currentGames: [
{
gameId: action.gameId,
gameSelections: [
{
subgameId: action.subgameId,
selection: action.selection
}
]
}
]
};
}
}

Immutable remove object entry react reducer

I want to immutable remove an object entry in react reducer
obj = {
selections: {}
}
this is how i add things to my selections obj
return {
...state,
selections: {
...state.selections,
[action.data.type]: action.data
}
};
this will give me
selections: {
test: { some funky data }
}
then when i want to remove test? How do i accomplish that?
Maybe something like this,
this.setState(state => {
return {
...state,
selections: {
...state.selections,
selections: delete state.selections.test
}
}
})
The best i could do for now is to set it to null
return {
...state,
selections: {
...state.selections,
[action.data.type]: null
}
};
its not firing the update when i use Object.assign and using delete
Just copy your state to a temporal variable, then delete the that you don't want:
//...
case 'REMOVE_PROPERTY':
//here we make a copy of selection object, note that this is a shallow copy
let newSelections = { ...state.selection };
delete newSelections[action.data.type];
return {
...state,
//here we overwrite selections object on a new created object before returning the value
selections: newSelections
};
//...

Updating state with nested array of objects

This is something also called as deep state update. Where I have to update nested state array.
I am implementing a simple redux application. Here I want to update the state which is nested array of object. My reducer function takes state, action. I have to update responses property of state with new value. I tried to map/iterate the state but it isnt working for me. Is there a way to update those specific values and return update state.
const sampleData = [{
"id": 1,
"text": "Hobby",
"answers": [{
"id": 1,
"text": "Chess",
"responses": 5
}]
}];
const action = {
type: "VOTE",
questionId: 1,
answerId: 3
};
This is handleSubmit function I am calling when Submit button is clicked on form.
handleSubmit(e){
const store = createStore(hobbyReducer, hobby); // created store here
var k = (document.querySelector('input[name = "hobby"]:checked').value);
store.dispatch({type:"SUBMIT", text: k, id: 1}); // Dispatching action to reducer
store.subscribe(()=>{
console.log(store.getState());
});
}
Here is reducer part of program:
function hobbyReducer(state, action) {
switch(action.type){
case "SUBMIT":
return{
...state,
answers: state.answers.map(e=> (e.text === action.text && e.answers.id === action.id)?
{ ...answers,
responses: (e.responses+1)} :
hobby )
}
break;
default:
return state;
}
}
initial state = sampleData; // Array object given above
I am unable to update the responses property which is in a nested array
This is the code I wanted to write, after some research I finally did what was required. Although this is not solution in terms of time complexity.
`
case "SUBMIT":
const updatedState = state.map(e =>{
if(e.id === action.id)
return{...e,
answers: e.answers.map(f =>{
if(f.text === action.text){
return{
...f,
...{responses: f.responses + 1},
}
}
return f;
})
}
return e;
})
console.log("updatedstate", updatedState)
return updatedState
Just an error in your map I think:
function hobbyReducer(state, action) {
switch(action.type) {
case "SUBMIT":
return {
...state,
answers: state.answers.map(answer => {
if (answer.text === action.text && answer.id === action.id) {
answer.response = answer.response + 1;
}
return answer;
});
}
default:
return state;
}
}

Resources