Skip to content

mc-petry/redux-handler

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

41 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

redux-handler

Powerful ๐Ÿ’ช and simple ๐Ÿ‘ˆ redux middleware to handle async actions.

Table of Contents

Requirements

peer dependencies: redux: ^4
optional dependencies: rxjs: ^6

Installation

store/index.ts

// Define your inner stores
interface RootStore {
  inner: InnerStore
}

// Combine it
const reducer = combineHandlers<RootStore>({
  inner: innerHandler
})

const store = createStore(reducer.buildReducer(), applyMiddleware(handlerMiddleware()))

store/handler.ts

export const { handler } = create<RootStore>()

Usage

Define store & handler:

interface Store {
  counter: number
}

const myHandler = handler<Store>({ counter: 0 })

// Create action
const myAction = myHandler
  .action() // For arguments use `.action<TArgs>`
  .pipe(
    // Operators
  )

Operators

Each pipe must contain single main operator

Main

sync

Handles standard action handler. Compatible operators: Common

sync((state, { args, type }) => typeof state)

rx

Handles rxjs observable. Compatible operators: Common, Async

rx((args, { action$, getState, type }) => Observable)

promise

Handles promise. Compatible operators: Common, Async

promise((args, { getState, type }) => Promise)

thunk

Handles async dispatch. Compatible operators: Common

thunk({ dispatch, getState, args } => void)

Async

pending

Occurs before async method is called.

pending((state, { args, type }) => void)

fulfilled

Occurs on async method succeeds.

fulfilled((state, { payload, args, type }) => typeof state)

rejected

Occurs on async method failed.

rejected((state, { error, args, type }) => typeof state)

completed

Occurs after async method is completed.

completed((state, { args, type }) => typeof state)

loading

Sets the property = true on pending. Sets the property = false on completed.

loading(prop: keyof state)

Common

available

Prevents calling actions based on state. Can be used only before main operator.

available((getState, { args, type }) => boolean)

Advanced

Handle action in another handler

myHandler.handle(
  myAction,
  // ...operators[]
)

Redux devtools

import { actionSanitizer } from 'redux-handler/utils'

const composeEnhancers: typeof compose = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
  ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ actionSanitizer })
  : compose

export const store = createStore(reducer, composeEnhancers(...composes))

Examples

Simple users fetch:

export interface UsersStore {
  data?: any[]
  loading?: boolean
}

export const usersHandler = handler<UsersStore>({})

export const fetchUsers = usersHandler
  .action<{ limit: number }>()
  .pipe(
    available((getState, { args }) => getState().users.data),
    rx(({ limit }) => ajax({ url: `/users?limit=${limit}` })),
    fulfilled((s, { payload }) => ({ ...s, data: payload })),
    loading('loading')
  )

Dispatch another action inside action:

export const updateUsersBalance = usersHandler
  .action()
  .pipe(
    sync(s => ({ ...s, balance: s.users.reduce((a, b) => a + b.balance, 0) }))
  )

export const fetchUsers = usersHandler
  .action()
  .pipe(
    rx(
      () => concat(
        ajax(),
        of(updateUsersBalance())
      )
    )
  )

Development

Publishing

npm run build
npm publish dist