Having this following data structure :
const foo = [
{
a: 'xxx',
b: 'xxx',
c: {
e: 'xxx',
...
}
}
...
]
Is it possible to access the value of e with this path object
const path = [0, 'c', 'e']
and edit it ?
I tried by doing
setResponseState(prevState => {
let data = prevState.responseData
path.forEach(id => data = data[id])
data = {}
return prevState
})
path being a context value but I found out data was a copy and therefore wasn't saved in the react state
Thank you
If you modify updating the last value in forEach as below should work for editing the object. Basically this avoid overriding the object reference and only update the value.
const foo = [
{
a: "xxx",
b: "xxx",
c: {
e: "xxx",
},
},
];
const path = [0, "c", "e"];
setResponseState((prevState) => {
let data = prevState.responseData;
path.forEach((id, i) =>
i === path.length - 1 ? (data[id] = {}) : (data = data[id])
);
return prevState;
});
Check this sample mutating the object
const foo = [
{
a: "xxx",
b: "xxx",
c: {
e: "xxx",
},
},
];
const path = [0, "c", "e"];
let data = foo;
path.forEach((id, i) =>
i === path.length - 1 ? (data[id] = {}) : (data = data[id])
);
console.log(foo)
If you just want to access the value, your existing code is mostly fine, you just need to return the value.
const foo = [
{
a: 'xxx',
b: 'xxx',
c: {
e: 'xxx',
}
}
]
const path = [0, 'c', 'e']
function setResponseState(prevState) {
let data = foo; //prevState.responseData
path.forEach(id => data = data[id])
return data;
};
console.log(setResponseState());
This (accessing a nested value via a provided path) is a standard task for the very expressive reduce method in collaboration with optional chaining in order to ensure a fail safe implementation ...
const foo = [{
a: "zzz",
b: "yyy",
c: {
e: "xxx",
},
}];
console.log({ foo });
console.log(
'[0, "c", "e"].reduce((value, key) => value?.[key], foo) ...',
[0, "c", "e"].reduce((value, key) => value?.[key], foo)
);
console.log(
'[0, "C", "e"].reduce((value, key) => value?.[key], foo) ...',
[0, "C", "e"].reduce((value, key) => value?.[key], foo)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
If it comes to mutating an object's nested property, one preferably would utilize the above approache within a function ...
const foo = [{
a: "zzz",
b: "yyy",
c: {
e: "xxx",
f: "uuu",
},
}];
function assignValueToExistingNestedProperty(type, path, value) {
const [lastKey, ...keyList] = path.reverse();
// access the next to last property value.
const reference = keyList
.reverse()
.reduce((value, key) => value?.[key], type);
Object.assign((reference ?? {}), { [lastKey]: value });
return type;
}
console.log({ foo });
console.log(
'assignValueToExistingNestedProperty(foo, [0, "c", "e"], "AAA") ...',
assignValueToExistingNestedProperty(foo, [0, "c", "e"], "AAA")
);
console.log(
'assignValueToExistingNestedProperty(foo, [0, "C", "e"], "BBB") ...',
assignValueToExistingNestedProperty(foo, [0, "C", "e"], "BBB")
);
console.log({ foo });
.as-console-wrapper { min-height: 100%!important; top: 0; }