I'm trying to replace or insert an array item (upsert) with existing ngxs state operators. I am currently using the following iif-statement. Is there an easier way to do this?
setState(
patch({
contractList: iif<Contract[]>(
contractList=>
contractList.some(
contract =>
contract.id === contractId
),
updateItem<Contract>(
contract =>
contract.id === contractId,
patch(loadedContract)
),
insertItem<Contract>(loadedContract)
)
})
)
State operators exist but it doesn't mean you're forced to use them, right. There is a recipe called Immutability Helpers. It's going to be published to the main site in 1-2 weeks.
If we're talking about state operators then it's possible to create custom operators, that's some kind of decomposition:
function insertOrUpdateContract(id: string, loadedContract?: Contract) {
return iif<Contract[]>(
contracts => contracts.some(contract => contract.id === id),
updateItem(contract => contract.id === id, patch(loadedContract)),
insertItem(loadedContract)
);
}
Thus there will be less code in your action handler and it will be more self-descriptive:
ctx.setState(
patch({ contractList: insertOrUpdateContract(contractId, loadedContract) })
);
Otherwise you could have used immer
library or something else preferred, that would save more code:
import { produce } from 'immer';
const state = produce(ctx.getState(), draft => {
const index = draft.contractList.findIndex(contract => contract.id === contractId);
// It exists then let's update
if (index > -1) {
draft.contractList[index] = loadedContract;
} else {
draft.contractList.push(loadedContract);
}
});
ctx.setState(state);
For sure immer
is an additional package for the project but it's very lightweight. It provides more declarative way to do such immutable updates. Choose what suits you best!
I would stop on some immutability helper when it comes to such complex state updates.