I'm trying to update a nested child in my state but always end up with an error saying 'cannot assign to read only property'. This is probably due the fact I'm working with immutable state. But how can I change that nested child then?
Here is the code:
@Action(UpdatePortalLogo)
updatePortalLogo(
ctx: StateContext<PortalStateModel>,
{ logo }: UpdatePortalLogo
) {
const state = ctx.getState();
let portal = state.portals.find((portal) => portal.id === state.portalId);
portal.style.logo = logo; //-> this is the line where it fails
ctx.setState(
patch({
portals: updateItem<Portal>(p => p.id === ctx.getState().portalId,
portal)
}));
}
My state model looks like this:
export interface PortalStateModel {
portals: Portal[];
portalId: string;
loaded: boolean;
loading: boolean;
}
Do I need to work with sub states for this to work?
This is because NGXS uses deepFreeze
in the development mode. You can check it up by:
console.log(Object.isFrozen(portal));
You can turn it off by setting developmentMode
to false
when importing root module:
NgxsModule.forRoot([], { developmentMode: false })
But you wouldn't want to do this as "freezing" prevents you of doing unpredictable mutations.
Destructing is your weapon:
const portal = { ...state.portals.find((portal) => portal.id === state.portalId) };
Also the updateItem
operator can take a function as the second argument where you can update your object. As a result the code becomes more declarative:
ctx.setState(
patch({
portals: updateItem(
portal => portal.id === state.portalId,
portal => {
const newPortal = { ...portal };
newPortal.style.logo = logo;
return newPortal;
}
)
})
);