Skip to content

choko-org/redux-rules

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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

About

Rules API for Redux applications.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages