What I try to achieve:
I want to update a value in an obj, which is part of the element of array. See the code below will give you better idea.
There is an issue that I update the value of object, via reference, instead of making a copy. This causes the state behave strangely.
I try to change it to making a copy, but I am not sure.
e.g.
const returnObj = {
...objs,
fields: [{name, value}, {name, value}, {name, value_update_this_only}, ...],
};
// This is the current code
export function* onChange(action) {
// get partial state from redux state
const list = yield select((state) => state.list);
let objs = list[action.index];
// * e.g. objs.fields === [{name, value}, {name, value}, ...]
// * basically following, find the correct field and update its value
// * following has problem, beause we change the value of a reference,
// * instead we should make a new copy, so redux can react
objs.fields.map((field) => {
if (field.name === action.fieldName) {
field["value"] = action.fieldValue;
}
return field;
});
// fire to redux reducer
yield put({
type: "UPDATE",
prop: obj,
docIndex: action.index,
});
}
// the problem: I don't know how to do it in destructing manner.
const returnObj = {
...objs,
fields: [],
};
I think rather than try and come up with a single destructuring statement that makes this work, it's easier to digest (and arguably more readable) in smaller steps:
objs
; call it copy
for nowfields
array and every item within itvalue
copy.fields
to the array created in 2// Step 1: Shallow copy
let copy = { ...objs }
// Step 2: Recreate fields and every item
let fields = copy.fields.map((field) => ({
...field
}))
// Step 3: Update value of desired item
fields.forEach((field) => {
if (field.name === action.fieldName)
field.value = action.fieldValue
})
// Step 4: Reassign fields to the copy
copy.fields = fields
Refactoring this, steps 2-4 can be combined into one step without sacrificing that much readability:
let copy = { ...objs }
copy.fields = copy.fields.map((field) => ({
...field,
value: field.name === action.fieldName ? action.fieldValue : field.value,
}))
It's been a long time since I've used redux or sagas, so I'm not sure whether fields
needs to be an entirely new array or if just the changed object within fields
needs to be new, but the above can be modified to accommodate either need.