Run Multistep Workflows with react-use-workflow

Oct 28, 2020

Update: public github and npm package.

$ yarn add @omarish/react-use-workflow

React-workflow is a lightweight framework to automate multi-step workflows. I designed it to streamline multi-step Web3.js transactions, but it can be used for any multi-step React workflow.

Here’s a demo with a three-step workflow:

https://omarish-assets.s3.us-east-1.amazonaws.com/images/2020-10-28/react-workflow-demo.webm

***How to use react-use-workflow*

There are two parts to adding a react-use-workflow:

  1. Define the workflow using the createWorkflow helper
  2. Add the workflow to a React component

Define the workflow using createWorkflow:

import { createWorkflow } from 'react-workflow'

const workflow = createWorkflow({
  steps: [
    {
      label: 'Permit Transfer',
      description: `Approve transfer of funds from to vault.`,

      /**
       * The logic to run a workflow step.
       *
       * The `context` specified by `getContext` below is passed in.
       */
      func: async context => {
        return await sleep(1000)
      },

      /**
       * value is optional. If not provided, it defaults to the label
       * in `MACRO_CASE`
       */
      value: 'APPROVE_TRANSFER',

      /**
       * Verify if the step has been completed. If not provided, the
       * step will be completed upon the promise passed to `func`
       * resolving.
       */
      verify: async () => {
        await sleep(2000)
        return true
      },
    },
    {
      label: 'Transfer Assets',
      description: 'Transferring the assets to your vault.',
      func: async (context = {}) => {
        return await sleep(2000)
      },
    },
    {
      label: 'Purchase Asset',
      description: 'Purchasing asset on the open market.',
      func: async (context = {}) => {
        return await sleep(3000)
      },
    },
  ],

  getContext: ({ stepNumber = undefined }) => {
    /**
     * Returns the execution context. Optionally specify a
     * stepNumber here if you want to provide a different context
     * based on the step.
     */return {}
  },
})

2. Mount the workflow using useWorkflow

Use the useWorkflow React hook to mount the workflow in a component.

import { useWorkflow } from 'react-workflow'
const Page = ({ workflow, ...props }: {
  workflow: Workflow
}) => {
  const { statuses } = useWorkflow(steps)
  return (
    <StepGuide steps={steps} statuses={statuses} />
  )
}

Proposed type definitions: these are a little hand-wavey, but I’ll firm them up if there’s enough demand for this library:

interface Workflow {
  workflow: Array<Step>,
  getContext: ({ stepNumber: undefined }: { stepNumber?: number }) => any
}

interface Step {
  // required
  label: string,
  description: string,
  func: IFuncWithContext,

  // optional
  verify?: IFuncWithContext,
  value?: string
}

type IFuncWithContext = (context: Map<any, any>) => Promise<any>

Want to use this?

$ yarn add @omarish/react-use-workflow

githubnpm package