ChainedReducer
Chained reducers allows you build a reducer using method chaining.
It utilizes immer hence state mutations are allowed.
Methods
constructor
In most cases, ChainedReducer will be provided by handle.reducer, hence you don't need to use constructor.
Arguments
initialState: object- the initial state.
import { ChainedReducer } from 'typeless';
new ChainedReducer({ foo: 'bar' })
attach(prop, reducer)
Attach a child reducer at the given path.
The child reducer will be only scoped to the nested state State[prop].
Arguments
prop: string- the property name.reducer: Reducer- the reducer to attach.
Returns
{ChainedReducer} - this reducer.
Example
interface Nested {
foo: string;
}
interface State {
sub: Nested;
}
const subReducer = new ChainedReducer({ foo: 'bar' } as Nested);
const reducer = new ChainedReducer(initialState as State)
.attach('sub', subReducer);
on(actionCreator, fn)
Attach a handler for the specific action creator. The action creator is a function generated by createModule.
Arguments
actionCreator: ActionCreator- the action creator.handler: (state, payload, action) => void
The function handler with the following parameters:state: object- the reducer state.payload: object- the action payload. The type is inferred automatically from ActionCreator.action: object- the original action.
Returns
{ChainedReducer} - this reducer.
Example
// interface.ts
import { createModule } from 'typeless';
import { UserSymbol } from './symbol';
const [handle, UserActions] = createModule(UserSymbol)
.withActions({
loadUser: (id: number) => ({ payload: { id } }),
userLoaded: (user: User) => ({ payload: { user } }),
});
// module.ts
import { handle, UserActions } from './interface';
interface State {
user: User | null;
}
const initialState: State = {
user: null,
};
handle
.reducer(initialState)
.on(UserActions.userLoaded, (state, { user }) => {
state.user = user;
});
onMany(actionCreators[], handler)
Attach a handler for multiple action creators. This function is very similar to on.
Arguments
actionCreators: ActionCreator[]- the action creators to match.handler: (state, payload, action) => EpicResult
Returns
{ChainedReducer} - this reducer.
Example
// interface.ts
import { createModule } from 'typeless';
import { UserSymbol } from './symbol';
const [handle, UserActions] = createModule(UserSymbol)
.withActions({
userLoaded: (user: User) => ({ payload: { user } }),
userUpdated: (user: User) => ({ payload: { user } }),
});
// module.ts
import { handle, UserActions } from './interface';
interface State {
user: User | null;
}
const initialState: State = {
user: null,
};
handle
.reducer(initialState)
.onMany(
[UserActions.userLoaded, UserActions.userUpdated],
(state, { user }) => {
state.user = user;
}
);
replace(actionCreator, fn)
Attach a handler for the specific action creator and replace the whole state.
Arguments
actionCreator: ActionCreator- the action creator. Under the hood it checksactionCreator.toString() === action.type.handler: (state, payload, action) => object
The function handler must return a new state object.
Returns
{ChainedReducer} - this reducer.
Example
// interface.ts
import { createModule } from 'typeless';
import { UserSymbol } from './symbol';
const [handle, UserActions] = createModule(UserSymbol)
.withActions({
reset: null,
});
// module.ts
import { handle, UserActions } from './interface';
interface State {
user: User | null;
}
const initialState: State = {
user: null,
};
handle
.reducer(initialState)
.replace(UserActions.reset, () => initialState);
nested(prop, fn)
Create a child reducer at the given path.
The child reducer will be only scoped to the nested state State[prop].
Arguments
prop: string- the property name.fn: (reducer: Reducer) => Reducer- the function to create a new reducer.
Returns
{ChainedReducer} - this reducer.
Example
// interface.ts
import { createModule } from 'typeless';
import { UserSymbol } from './symbol';
const [handle, UserActions] = createModule(UserSymbol)
.withActions({
reset: null,
setFilter: (filter: string) => ({ payload: { filter } }),
});
// module.ts
import { handle, UserActions } from './interface';
interface State {
foo: string;
search: {
filter: string;
};
}
const initialState: State = {
foo: 'bar',
search: {
filter: '',
},
};
handle
.reducer(initialState)
.nested('search', searchReducer =>
searchReducer.on(UserActions.setFilter, (state, { filter }) => {
state.filter = filter;
})
);