flux-payload-action

Simplified Flux Action, with 'type' and 'payload' properties only, compatible to FSA

Usage no npm install needed!

<script type="module">
  import fluxPayloadAction from 'https://cdn.skypack.dev/flux-payload-action';
</script>

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);