Store

The Store package is a kernel that exposes an API using the storeHelper to manage the Redux's state.

Store Helper

The storeHelper is responsible for the application state management. It's a wrapper around Redux, which exposes the required methods to handle the state of the application.

You should be familiar with the Redux documentation.

Method

Description

getState

Obtains the Redux store state

registerReducer

Registers a plugin reducer

dispatch

Dispatches an action

handleAction

Handles an action

handleReducedAction

Handles an action after the reducer

Usage

The store helper is a wrapper that enables Redux capacities. It uses a Redux store under the hood. Redux philosophy consists of three key concepts:

  • The state

  • The reducer

  • The actions

getState

The state is an object that contains all the application state. It is the single source of truth.

Use getState to obtain the state.

Copy
storeHelper.getState(): State

registerReducer

By default, the state for plugins is empty. In Redux, reducers are functions that update the state. These reducers receive the old state, and they have to compute a new state. Before writing a reducer, you must understand that they are:

  • They are pure functions.

  • They cannot modify the state; they make a copy instead.

  • They cannot modify any global variable.

  • It returns the state.

Redux uses reducers to execute actions and notify views of the new values. It automatically decides when to call reducers.

Register your plugin reducers with registerReducer. The first thing that you have to do with a reducer is set up the initial state. The typical form to set it up is by using the default argument value syntax.

dispatch

The Redux store executes all actions in the system. In Redux, actions are JSON objects that have at least one property called type, which is a string. Actions may have more related properties for that action type.

Copy
{
  "type": "counter/INCREMENT",
  "amount": 1
}

Use dispatch to request redux to execute one of these actions.

Reducers compute dispatched actions. Besides the state, reducers receive the current action as a second argument. By convention, the reducer starts with a switch statement that looks for the value of the action type. This switch always has a default case that returns the state without modification; it is because the reducer must ignore unknown actions. If the action type is relevant, it adds a case statement in which it computes the next state.

handleAction

Adds a listener of actions, which triggers a callback (handle) when a condition (test) is satisfied.

Different plugins can be handling the same action, so we use chain of responsibility pattern with a priority. The plugins with a lower priority will be handled first.

Usage
Copy
handleAction(test: String, handle: HandleFunction, position?: ActionHandlerPosition): void
  • test String

    Condition to determine if the action should be handled or not.

  • handle HandleFunction

    The callback function which will handle the action.

  • position ActionHandlerPosition [OPTIONAL]

    The object with the position of the action to be handled.

  • HandleFunction: ({action, replaceAction, stopPropagation, preventDefault, done }) => Promise?

    Function that handles an action and returns a promise if it must wait to the completion of a promise. Look examples for usage.

  • ActionHandlerPosition: { name: string, before: string, after: string }

    Object that defines the position of the action to be handled in relation to an existing one.

Returns
  • Function

    A function to stop handling the action.

Warning: Using handleAction with a function as test argument can negatively affect the performance of the application, if not used carefully.

The recommendation is to avoid its use unless there is no alternative. Only use it when the action to be handled does not depend on a type which can be matched by a String or a RegExp.

For example, instead of:

Copy
handleAction(
  (action) => action.type === 'INCREMENT' && action.count > 2,
  () => { ... },
)

You can use:

Copy
handleAction(
  'INCREMENT',
  (action) => {
    if (action.count > 2) { ... }
  },
)

 

When handling an action the handled action is retrieved:

Copy
storeHelper.handleAction('INCREMENT', ({ action }) => {
  console.log('Log: ', action), { name: 'incrementAction' };
});

When handling an action, by default, the handler respects the priority of the plugin, but a priority for the handlers can be specified with the position parameter: package.json

Copy
{
  "name": "pos-web-plugin-example",
  "version": "0.0.1",
  "orion": {
    "storeHelper": {
      "actionHandlers": {
        "produces": ["someAction"]
      }
    }
  }
}
Copy
storeHelper.handleAction('someAction', ({ action }) => console.log('Hello ', action), {
  name: 'someAction',
});
storeHelper.handleAction('anotherAction', ({ action }) => console.log(action, ' goes before'), {
  before: 'someAction',
});

// this logs: anotherAction goes before, Hello someAction

Action handlers can be asynchronous:

Copy
storeHelper.handleAction('INCREMENT', async ({ action }) => {
  await delay(1000); // Will delay the flow of the action 1 second
});

handleReducedAction

Use this method to handle an action (due to its type) after the state has been modified. In other words, after the action has passed through the reducers.

Useful to react to the state changes.

These kind of handlers can not be skipped.

Usage
Copy
handleReducedAction(test: String, handle: Function): void
  • test String

    The type of the action which determines if the action should be handled or not.

  • handle Function

    The callback to be invoked when the action is handled.

Returns
  • Function

    A function to stop handling the reduced action.