Hard reducer
Type friendly reducer helper
- Type safe interface - Avoid redundant `type` string definitions - Keep reducer interface `(State, Action) => State` to use with `redux.combineReducers()` - Handle Flux Standard Action `{ type: string, payload: Payload }` The project is written primarily in JavaScript, first published in 2018. Key topics include: flowtype, fsa, reducer, redux, typescript.
hard-reducer
Type friendly facade for better reducer.
shnpm install hard-reducer --save # or yarn add hard-reducer
Concepts
- Type safe interface
- Avoid redundant
typestring definitions - Keep reducer interface
(State, Action) => Stateto use withredux.combineReducers() - Handle Flux Standard Action
<Payload>{ type: string, payload: Payload }
Check this code to know detail.
Examples
This code is runnable in both flowtype and typescript
js/* @flow */ // ^ flow magic comment to activate. It will be ignored in typescript. import { buildActionCreator, createReducer, type ActionCreator } from "hard-reducer"; // ^ If you use typescript, Do not use `type` before ActionCreator const { createAction } = buildActionCreator({ prefix: "counter/" }); // Add type to your payload by ActionCreator const inc: ActionCreator<number> = createAction("inc"); // or infer by function result const dec = createAction("dec", (val: number) => val); inc(1); //=> { type: 'counter/inc', payload: 1 } // Define state type type State = { value: number }; const initialState: State = { value: 0 }; const reducer = createReducer(initialState) // Handle `(State, Payload) => State` in matched context. .case(inc, (state, payload) => { return { value: state.value + payload }; }) .case(dec, (state, payload) => { // $ExpectError const p: string = payload; return { value: state.value - payload }; }) // Take string .case("other/noop", (state, payload) => { return state; }) // Take all uncaught action, not payload! .else((state, action) => { console.log("default fallback"); return state; }); // Use it const ret0 = reducer(initialState, inc(3)); const ret1 = reducer(ret1, dec(1));
See detail in index.js.flow or index.d.ts
Handle async action: createAsyncAction
createAsyncAction(...) returns { resolved, rejected, started } and callable method.
(You need to add redux-thunk in store's middlewares)
js/* @flow */ import { createReducer, buildActionCreator } from "hard-reducer"; const { createAsyncAction } = buildActionCreator(); const incAsync = createAsyncAction("inc-async", async (val: number) => { if (val % 2 === 1) { throw new Error("error"); } return { p: 1 }; }); type Status = "ready" | "started" | "resolved" | "rejected"; type State = { status: Status, payload: ?{ p: number } }; const reducer = createReducer({ status: "ready", payload: null }) .case(incAsync.started, state => { return { state: "started" }; }) .case(incAsync.resolved, (state, payload) => { return { state: "resolve", payload }; }) .case(incAsync.rejected, (state, error) => { return { state: "ready", payload: null }; }); // store import reduxThunk from "redux-thunk"; import { applyMiddleware, createStore } from "redux"; const store = createStore(reducer, undefined, applyMiddleware(reduxThunk)); store.subscribe((...args) => { console.log("store", store.getState()); }); // dispatch store.dispatch(incAsync(1));
Handle thunk action: createThunkAction
createThunkAction(...) returns { resolved, rejected, started } and callable method.
(You need to add redux-thunk in store's middlewares)
jsimport { createReducer, buildActionCreator } from "hard-reducer"; const { createThunkAction, createAction } = buildActionCreator(); const inc = createAction("inc", (val: number) => val); const thunked = createThunkAction( "thunked", async (input, dispatch, getState) => { dispatch(inc(input.value)); return { ret: true }; } ); // Handle createReducer({ status: "ready", payload: null }) .case(thunked.started, state => { return { state: "started", payload: null }; }) .case(thunked.resolved, (state, payload) => { return { state: "resolve", payload }; }) .case(thunked.rejected, (state, error) => { return { state: "ready", payload: null }; }); // dispatch store.dispatch(thunked({ value: 1 }));
Related projects
- reduxactions/redux-actions: Flux Standard Action utilities for Redux.
- aikoven/typescript-fsa: Type-safe action creator utilities
- acdlite/flux-standard-action: A human-friendly standard for Flux action objects.
ChangeLog
See ChangeLog.md
LICENSE
MIT
Contributors
Showing top 5 contributors by commit count.
