# redux-workflows

> A library for defining complex workflows spanning multiple screens, without relying on routes or complex state management

Latest version **0.0.3** (published 2018-07-23) · MIT license · 0 weekly downloads

> **Deprecated.** This package is deprecated.

## Install

```sh
npm install redux-workflows
pnpm add redux-workflows
yarn add redux-workflows
bun add redux-workflows
```

## Health

**Score 10/100 (F)** — status: deprecated.

Negative: deprecated.

## Facts

| | |
|---|---|
| Version | 0.0.3 |
| Published | 2018-07-23 |
| First published | 2018-07-16 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | ESM + CommonJS |
| Dependencies | 1 |
| Unpacked size | 59.6 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | James Philipps |
| Maintainers | jp2018dev |

## Links

- npm: https://www.npmjs.com/package/redux-workflows
- npm.io page: https://npm.io/package/redux-workflows

## Dependencies (1)

- [redux-thunk](https://npm.io/package/redux-thunk.md) ^2.3.0

## Recent versions

- 0.0.3 (latest) — 2018-07-23
- 0.0.2 — 2018-07-23
- 0.0.1 — 2018-07-16

## README

# redux-workflows

> A library for defining complex workflows spanning multiple screens, without relying on routes or complex state 
management. Whilst this library can be used for multiple page forms, it is agnostic as to its contents so is suitable 
for a wide variety of workflows

[![NPM](https://img.shields.io/npm/v/redux-workflows.svg)](https://www.npmjs.com/package/redux-workflows) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)

## Install

```bash
npm install --save redux-workflows
```

## Usage

### Concepts
Many Workflow models rely on a single definition to control all of their interactions, entry and exit points. This 
quickly gets messy and difficult to modify. redux-workflows tries another approach by delegating this control to its 
components. This allows for much more flexibility at the cost of not having a single point of reference for the whole 
flow. You should examine the use case for your Workflow carefully and determine whether this approach is appropriate. 
  
redux-workflows relies on a few key concepts to allow users to quickly define their flows:

#### Workflow 
A Workflow is the top level element of redux-workflows, and contains a series of Stages. It must be specified with a 
unique name and an initial stage that corresponds to one of its child stages.
 
The Workflow lifecycle is as follows:

* **Initialisation** - Happens when the Workflow is mounted and creates an entry in the Redux store for this workflow. 
    If a previous workflow entry exists for this workflow name, it is overwritten.
* **Render** - The component corresponding to the Workflow's initial stage is rendered.
* **Data Manipulation** - The stage can programmatically push data to, or pull data from the Redux store, allowing data 
    to be persisted between screens (or reloaded when the stage is entered again). There are deliberately very few 
    restrictions on the shape of the data to allow maximum flexibility. Data is keyed by stage to make retrieval easier  
* **Transitions** - Stages can request a transition to any other stage in the workflow at any time. This will cause the 
    current stage to unmount and the new stage to render. Any data not persisted will be lost
* **Completion** - Any stage can signal completion of the Workflow (allowing for multiple exit points). Once the 
    Workflow is completed, the *onComplete* callback that can be specified in the Workflow definition is invoked and 
    passed all of the data persisted during the Workflow's lifecycle. Finally, the workflow state is removed from the 
    Redux store 
 
#### Stage 
A Stage is a child element of the Workflow. It is specified with a unique (within the Workflow) name and a component 
to render. This component can be a pure React class/function or a higher-order or connected component. Any additional 
props specified on a stage will be passed down to its rendered component 

There must be at least one, initial, stage in a Workflow and there is no upper limit. Stages can be specified in any order.

#### Flow Accessor 
The Workflow mechanics are exposed to each rendered component via a prop named **flow**. The component can, at any 
point, invoke any of the Flow Accessor's functions to control the state of the Workflow. For example, the component can:

* Save/Load data for any Stage (defaulted to the current stage)
* Transition to another stage
* Subscribe/Unsubscribe to Asynchronous events
* Determine if an Asynchronous event has completed
* Complete the Workflow

The flexibility of this approach makes it trivial to implement multiple entry/exit points to a workflow and easily step 
forwards/backwards through a user journey.

### Simple Example 
Below is a simple example of rendering and transitioning between two stages. For a more comprehensive and executable 
example, see the `example` folder

```javascript
import React, {Component} from 'react'
import {Stage, Workflow} from 'redux-workflows'

const FirstStage = ({flow}) => (
  <button onClick={flow.transitionTo('s2')}>Go to step 2</button>
)

const SecondStage = ({flow}) => (
  <button onClick={flow.complete()}>Complete the Workflow</button>
)

class App extends Component {
  render() {
    const onComplete = () => console.log("Workflow Complete!")
    return (
      <Workflow name='test-flow' initialStage='s1' onComplete={onComplete}>
        <Stage name='s1' component={FirstStage}/>
        <Stage name='s2' component={SecondStage}/>
      </Workflow>
    )
  }
}
```

### Asynchronous Events
It is often desirable to transition based on the outcome of an Asynchronous event (e.g. a success/failure of a http 
request). redux-workflows provides a standard pattern for doing this via the Flow Accessor:

1. Subscribe to the action that indicates your Async event has completed
2. Start your Async event
3. Implement a check in your *componentDidUpdate()* method to determine when this action has occurred
4. Unsubscribe from this action

**Note**: *A workflow will always be notified that an action has occured **after** it has been fully processed by 
middleware and reducers*

#### Example 
In the below code, we will request a token asynchronously. We will wait for a REQUEST_TOKEN_COMPLETE action before 
transitioning to the next stage of the workflow. For brevity, the actual workflow definition is omitted, but a full 
async example can be found in the `example` folder.

```javascript
import React, {Component} from 'react'
class TokenRequestPage extends Component{
  
  componentDidUpdate() {
    const {flow} = this.props

    if (flow.isActionObserved('REQUEST_TOKEN_COMPLETE')) {
      flow.unsubscribe('REQUEST_TOKEN_COMPLETE')
      flow.transitionTo('afterTokenRequestStage')
    }
  }
  
  render(){
    return <button onClick={this.props.requestToken}>Request Token</button>
  }
}
```



## API

### Workflow

Wrapper element containing a set of stages that make up the workflow. Only one stage will be rendered at a time. 
Transitions are handled by the stages themselves 

* **name** *(Required*): A **unique** identifier for this flow, to be used as a key in the Redux store. Must correspond to 
      the name of a child Stage element.  
* **initialStage** *(Required*): The name of first stage to be rendered when this workflow initialises 
* **reduxStoreKey** *(Optional): Override the key that the workflow will use to store its state. Default: **reduxWorkflow** 
* **onComplete** *(Optional): A callback that will be invoked when the flow.complete() function is called from within any 
      stage.  

### Stage

A child of the Workflow element that represents one step of the workflow. 

Note that stages need not be specified in the 
order that they are visited and not all stages need to appear in the workflow (e.g. branching journeys)

* **name** *(Required*): A **unique** identifier within this workflow for this stage, to be used as a key in the Redux store 
* **component** *(Required*): The component to be rendered when this stage is selected 

### Flow Accessor

An object provided to every rendered component (as the property: 'flow') specified by a Stage within a Workflow, 
which allows access to the workflow from within the Stage


* **name**: The name of the Workflow
* **currentStage**: String containing the name of the current rendered Stage
* **transitionTo(stage)**: Transitions the workflow to the specified Stage
  * **stage** *(Required)*: The Stage name to transition to 
* **saveStage(data, stage)**: Saves an arbitrary data object against the stage identifier in the Redux store
  * **data** *(Required)*: Arbitrary object containing data to save 
      (e.g.:`{ FOO: 'BAR', BAZ: [ 'A', 'B'] }`)
  * **stage** *(Optional)*: The Stage name to save this data against. If not specified, 
      data will be saved against the currently active Stage. 
      **WARNING**: *Be careful using saveStage without a specific stage in the component lifecycle methods 
      (e.g. componentWillUnmount) as the currentStage may have changed at this point, causing unexpected behaviour.*
* **loadStage(stage)**: Loads data stored against the stage identifier in the Redux store. Returns undefined if there 
      is no data saved against this Stage
  * **stage** *(Optional)*: The Stage name to load this data against. If not specified, 
      data will be saved against the currently active Stage

* **complete()**: Completes the Workflow and triggers the provided onComplete callback

* **subscribe(actionType)**: Subscribe this workflow to observe actions of the given actionType
* **unsubscribe(actionType)**: Unsubscribe this workflow from being able to observe actions of the given actionType. 
      Also clears any currently observed actions.
* **isActionObserved(actionType)**: Returns true if the action has occurred since the workflow subscribed to it

## Example
A full demo application (with source) is included in the example directory at the project root.
 
To run the example:
```bash
cd example
yarn
yarn start
```

Then in your browser, navigate to [http://localhost:3000](http://localhost:3000)

## Contributing

TODO


## License

MIT © pillie2005/redux-workflows (https://github.com/pillie2005/redux-workflows)

---
_Source: https://npm.io/package/redux-workflows · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
