Skip to content

Latest commit

 

History

History
116 lines (91 loc) · 3.4 KB

README.md

File metadata and controls

116 lines (91 loc) · 3.4 KB

Rules API for Redux

Make your code more easy to reason about with a more natural language for your logic, using rules fired by actions and reacting to a given set of facts.

Based on the forward-chaining rules in Clojure called Clara and a discussion from an issue of Choko core.

Build Status

Where Redux gets in?

[ACTION] => ([RULES] -> [CONDITIONS] -> [REACTIONS]) => [STATE]

Obs.: Reactions are dispatched actions / side-effects.

Redux gives us the tools to build functional rules systems using it's middleware API. So basically each rule behaves like a Redux's middleware.

Vanilla Redux:

import { createStore, applyMiddleware} from 'redux'
import { flashMessage, FLASH_MESSAGE } from 'app/modules/messages/actions'

const LOGIN_SUCCESS = 'user/login/SUCCESS'

const welcomeAuthUserMiddleware = store => next => action => {
  switch (action.type) {
    case LOGIN_SUCCESS:
      if (action.payload.user.roles.some(role => role === 'authenticated')) {
        const { name, lastLogin } = action.payload.user
        if (!!lastLogin) {
          store.dispatch(flashMessage('Good to see you ' + name + '!'))
        }
      }
      break;
  }
  return next(action)
}

const reducer = (state, action) => {
  if (action.type === LOGIN_SUCCESS) {
    return { ...state, user: action.payload.user }
  }

  if (action.type === FLASH_MESSAGE) {
    return { ...state, message: action.payload }
  }
}

const store = createStore(reducer, applyMiddleware(welcomeAuthUserMiddleware))

store.dispatch({
  type: LOGIN_SUCCESS,
  payload: { user: { name: 'Manolo', roles: ['authenticated'] } }
})

console.log(getState().message) // Good to see you Manolo!

Using Redux Rules:

import { createStore, applyMiddleware } from 'redux'
import combineRules, { every } from 'redux-rules'
import { flashMessage, FLASH_MESSAGE } from 'app/modules/messages/actions'

const LOGIN_SUCCESS = 'user/login/SUCCESS'

const isAuthUser = ({ action }) => action.payload
  .user.roles.some(role => role === 'authenticated')
const isComingBackUser = ({ action }) => !!action.payload.user.lastLogin

const welcomeAuthUserMessageRule = {
  type: 'messages/user/login/SUCCESS',
  actionTypes: [LOGIN_SUCCESS],
  condition: every([
    isAuthUser, isComingBackUser
  ]),
  reaction: store => next => action => {
    const { name } = action.payload.user
    store.dispatch(flashMessage('Good to see you ' + name + '!'))
    return next(action)
  }
}

const rulesMiddleware = combineRules({
  rules: [welcomeAuthUserMessageRule]
})

const reducer = (state, action) => {
  if (action.type === LOGIN_SUCCESS) {
    return { ...state, user: action.payload.user }
  }

  if (action.type === FLASH_MESSAGE) {
    return { ...state, message: action.payload }
  }
}

const store = createStore(reducer, applyMiddleware(rulesMiddleware))

store.dispatch({
  type: LOGIN_SUCCESS,
  payload: { user: { name: 'Manolo', roles: ['authenticated'] } }
})

console.log(getState().message) // Good to see you Manolo!

Usage:

LICENSE

MIT