holochain / hc-redux-middleware

a few methods of redux middleware for holochain UI apps
28 stars 5 forks source link

hc-redux-middleware

To install: npm install --save @holochain/hc-redux-middleware

Usage

Configure the store to use the middleware

import { createStore, combineReducers, applyMiddleware } from 'redux'

import { connect } from '@holochain/hc-web-client'
import { holochainMiddleware } from '@holochain/hc-redux-middleware'

// this url should use the same port set up the holochain container
const url = 'ws://localhost:3000'
const hcWc = connect({ url })

const middleware = [holochainMiddleware(hcWc)]

...

let store = createStore(reducer, applyMiddleware(...middleware))

Lets look an example action to see how the middleware works

{
  type: 'CALL_HOLOCHAIN_FUNC',
  payload: { ... }
  meta: { 
    holochainZomeCallAction: true, 
    instanceId: 'someInstance',
    zome: 'someZome',
    func: 'someFunc'
  }
}

The first thing to notice is the meta.holochainZomeCallAction = True. This is how the middleware detects which actions it should use to make calls to holochain.

The payload will be passed directly to the call to the holochain function and must have fields that match the holochain function signature.

Action creators

To abstract away from manually creating these actions this module also provides helpers for doing that. For a particular holochain function call it will create an action creator that you can call later with parameters

import { createHolochainZomeCallAsyncAction } from '@holochain/hc-redux-middleware'

const someFuncActionCreator = createHolochainZomeCallAsyncAction('someInstance', 'someZome', 'someFunc')

// later on when you want to create dispatch an action to call the function with some params
const action = someFuncActionCreator.create(params)
dispatch(action) // this returns a promise that resolves with the response or fails with the error

This will autocomplete the type field using the format someApp/someZome/someFunc. You can also use the autogenerated holochainAction.success().type and holochainAction.failure().type

It is also possible to create actions to make conductor admin calls. These are via a different action creator createHolochainAdminAsyncAction. These take a single call string such as admin/instances/list or admin/dna/install. See the conductor documentation for the full admin functionality. This will not be required for most hApps.

Response Actions

When a successful call to holochain is completed the middleware will dispatch an action containing the response. These actions have a type that is the same as the call but with _SUCCESS or _FAILURE appended.

{
  type: 'CALL_HOLOCHAIN_FUNC_SUCCESS',
  payload: { ... } // this contains the function call result
}

{
  type: 'someApp/someZome/someCapability/someFunc_FAILURE',
  payload: { ... } // this contains details of the error
}

These can then be handler by the reducer to update the state

Special actions

There are also several actions that the middleware will dispatch automatically. Currently these are

Typescript support

We love typescript and so the action creators ship with typescript definitions and type support out of the box! The typed actions are based off the typesafe actions model. Holochain action creators can be made using generics to match the function parameters and return type of the zome function

import { createHolochainZomeCallAsyncAction } from '@holochain/hc-redux-middleware'

export const someFuncActionCreator = createHolochainZomeCallAsyncAction<ParamType, ResponseType>('someApp', 'someZome', 'someFunc')

// The params must match the ParamType or this will error
const action = someFuncActionCreator.create(params)

This is even more useful in the reducer.

import { getType } from 'typesafe-actions'

export function reducer (state = initialState, action: AnyAction) {
  switch (action.type) {
    case getType(someFuncActionCreator.success):
      // The type checker now knows that action.payload has type
      // set in the definition using the generic
      // You literally cant go wrong!

    ...
  }

See [https://github.com/piotrwitek/typesafe-actions] for all the details of using typesafe actions