I want to store some data in the state. The problem is that I have to add it one by one dynamically dispatching an action. I tried two solutions: Record<string, number> and Map<string, number>.
Record is thrwoing an error in the reducer method that says the object is not extensible.
With Map I have a different problem: Detected unserializable state at "airplanes.aircraftRotation"
Maybe I did something wrong while implementing these methods:
export interface State extends EntityState<Airplane> {
error?: any;
aircraftRotation: Map<string, number>;
}
export const initialState: State = airplanesAdapter.getInitialState({
error: null,
aircraftRotation: new Map<string, number>(),
});
export default State;
And the reducer:
function updateAircraftRotation(state: State, aircraftCallSing: string, rotation: number): State {
state.aircraftRotation.set(aircraftCallSing, rotation);
return state;
}
Can someone give me some hint how to do this correctly?
A Map is not a fully serializable value, and so RTK will always warn about this.
The better approach here is to use a plain JS object instead, especially since your Map just has string keys.
I think you are not returning your store in the reducer properly. As your are using a Map object which might not be immutable/serializable., this might cause issues as raised here.
When ngrx store state contains a Map, why are changes to this Map not recognized?
you might want to try something like this in your reducer. Where you "clone" the Map, and the new copy will allow the data to be serializable?
function updateAircraftRotation(state: State, aircraftCallSing: string, rotation: number): State {
let aircraftRotation = new Map(state.aircraftRotation)
aircraftRotation.set(aircraftCallSing, rotation);
return {...state,aircraftRotation } ;
}
It's a best practice that you should not store any data in Redux if it is not serializable. A Map object is not serializable because it has instance methods such as set() which will be lost if converting to and from JSON.
The TypeScript type Record<string, number> describes any object with string keys and number values. This is the correct type to use, but you'll want to implement it with a plain object instead of your new Map<string, number>().
The initial value would just be an empty object {}.
export interface State extends EntityState<Airplane> {
error?: any;
aircraftRotation: Record<string, number>;
}
export const initialState: State = airplanesAdapter.getInitialState({
error: null,
aircraftRotation: {},
});
In your reducer, you no longer have the set method from the Map so you will need to update your object differently.
I'm confused by your reducer code as I'm seeing two arbitrary arguments and no action.
You'll probably need to return a new object which copies all of the properties of the previous, like this:
return {
...state,
aircraftRotation: {
...state.aircraftRotation,
[aircraftCallSing]: rotation
}
}
With immutability middleware (Redux Toolkit), you can just set the property directly, like this:
state.aircraftRotation[aircraftCallSing] = rotation;