README
Flux Payload Action
FPA is an implementation of flux action, which is really easy to understand and use.
In FPA, there's type
and payload
properties only, no error
, no meta
, which avoid the complexity of overload and corner cases.
And by design, FPA supports the following attributes:
- Type-safe with any string type.
- Compatible to Flux Standard Action (FSA).
interface Fpa<TP> {
type: string;
payload: TP;
}
Read A rethink of Type-safe Actions (Confluence Page) for more information about the design.
Usage
import { ActionCreator } from "flux-payload-action";
type AnyAction = { type: string }; // maybe import from 'redux'
const ns = "sample-app-module";
// firstly, create an action creator by type name and a specific payload type,
const actionCreator = ActionCreator<number>(`${ns}/balabala`);
// you can create action instance by the 'create' method,
const action = actionCreator(1.1); // Fpa<number>
// and use type guard in reducer,
const reducer = (state: number = 0, action: AnyAction): number => {
// move switch-case style to if-else style
if (actionCreator.match(action)) {
// Type guards: action is Fpa<number>
return action.payload; // number
}
// default branch
return state;
}
// actually, you can narrow the type everywhere you need,
let action: AnyAction;
if (actionCreator.match(action)) {
// action is Fpa<number>
// ...
}
Migration Guide
typesafe-actions
For action creating,
// For single action,
// from typesafe-actions style
const action = createStandardAction("T")<T>();
// to flux-payload-action style
const action = ActionCreator<T>("T");
// For async action group
// from typesafe-actions style
const actions = createAsyncAction("T1", "T2", "T3")<T1, T2, T3>();
// to flux-payload-action style
const actions = AsyncGroupCreator<T1, T2, T3>("T");
For usage in reducer,
let action1; // Assume there're several action creators
let action2; // ...etc
// from typesafe-actions style
type ActionTypes = ActionType<typeof action1 | typeof action2>;
const reducer = (state, action: ActionTypes) => {
switch (action.type) {
case getType(action1): {
// Type guards for action1
return f1(state, action);
}
case getType(action2): {
// Type guards for action2
return f2(state, action);
}
default: {
return state;
}
}
}
// to flux-payload-action style
const reducer = (state, action: { type: string }) => {
if (action1.match(action)) {
// Type guards for action1
return f1(state, action);
}
if (action2.match(action)) {
// Type guards for action2
return f2(state, action);
}
return state;
}
For usage in saga,
let actionCreator; // Assume there's an action creator
// from typesafe-actions style
const action: ActionType<typeof actionCreator> = yield take(getType(actionCreator));
// to flux-payload-action style
const action: ReturnType<typeof actionCreator> = yield take(actionCreator.match);
// from typesafe-actions style
takeLatest(getType(actionCreator), handler);
// to flux-payload-action style
takeLatest(actionCreator.match, handler);