We tend to split our redux code into two “sections”, an action function and a reducer function which usually uses a switch to then return state based upon the supplied action.
Actions
An action can be thought of (within Redux) as a message or something that happens (hence an action). We might write an action creator as a function, like the following
export const onLoad = (name: string) => { return { type: ActionType.Load, payload: name }; };
this returns the action which has a shape of
{ type, payload }
The type is required (as this is what we switch in the reducer) but the payload might not be, depending upon the action.
Alternatively we might dispatch an action using the redux store, for example
store.dispatch({ type: ActionType.Load, payload: name });
The key thing when creating actions is that they should not change anything but should simply state that some action should be taken and pass any data required within the reducer.
Note: the payload can be of more complex types, usually the type is simply a string representing the name of the action.
Reducers
Reducers responds to our action messages. The usual way to write a reducer is to have a function like the following
export default (state: any = initialState, action): any => { switch (action.type) { case ActionType.Load: return { ...state, queryName: action.payload }; // ... } return state; }
So we simply switch, based upon the action type (hence we’d usually have the action type string as a const, which must be unique across all your application reducers, hence a style such as the following is not unusual, where we prefix the action type value with some form of namespace followed by the action name
export enum ActionType { Load = "myapp/load", // ... }
We can clone and add different values to the state using either the spread operator, i.e.
{ ...state, queryName: action.payload }
or via
Object.assign({}, state, { queryName: action.payload });
Rules for reducers
- Must always return the state even if no changes are made an even if the state is null but must never return undefined.
- Treat state as immutable, hence do not change state but simply return new state (which might be cloned and with changes from the previous state).
- A reducer should process every action even if it just simply returns the original state.