Hope someone can help me with an easier way of updating my recoil states on more complex objects/arrays. I'm mainly a C# developer, but trying to learn some decent ways of coding javascript. This just seems to ugly and overcomplicated, the way my code looks currently.
As the state instance is read only, I cannot change values on it directly. Using underscores clone method does even not change that.
So here's my simplified objects, in real life the have a lot of non relevant properties:
interface IDeviceAttributeValue {
/** The unique value key
id: string;
/** The attribute value */
value: any;
}
interface IDeviceAttribute {
/** A unique key to identify the attribute. Normally the OSC address of the setting is used */
key: string;
/** The list of attribute values */
values: IDeviceAttributeValue[];
}
In React i have the state declaration
const [attribute, setAttribute] = useState(props.attribute as IDeviceAttribute);
Or some other place a Recoil state: const [deviceAttributeState, setDeviceAttributeState] = useRecoilState(recoilDeviceAttributeState);
And somewhere in the code I need to change a value on the value array and update the state. In both cases with React state and Recoil state, then the 'getter' instance is readonly/const.
I end up with this:
... code calculating a new value for existing value in editedSetting: IDeviceAttributeValue
...
// Now update state, first find the element in the array
let index = attribute.values.findIndex(l => l.id === editedSetting.id);
if (index !== -1) {
let newValueItem = {
...attribute.values[index],
value: newValue
}
setAttribute({
...attribute,
values: [...attribute.values.slice(0,index - 1), newValueItem,
...attribute.values.slice(index + 1)]
})
}
So many lines of code for a simple state update! I'm sure for someone this is very trivial task and can be done much more elegant:-)
Thanks for help and time
Ok, seems like there's no way to update object/array based states without using spread operator and taking care of deep updating as the shallow property update only works on top level.
This means that you must take care of providing the existing property values from current state, and set the ones you wanna change in parallel, and this you need to do on each nesting level.
I found a nice q/a providing examples here: blog
So in my case I ended up with code like this for updating an object with a array property (settings) with a new value for one specific element in the array:
setEditedDeviceState(curVal => ({
...curVal,
settings: curVal.settings.map(
el => el.key === attribute.key ? attribute : el
)
}));
I must admin that I find this to be a pain in the ... and a candidate to easily introduce errors in your data models. If this is a lack in the language itself or the implementation of react (recoil, redux or whatever) states is probably something that can be discussed further. But seems like this is what you have to live with currently.