Home

Awesome

<h1 align="center"> <img width="320" src="docs/raj.svg" alt="Raj"> <br> <br> </h1>

The Elm Architecture for JavaScript

npm install raj

npm Build Status Greenkeeper badge

Features

Check out the homepage for resources and ecosystem packages.

Example

A counter that increments by one every time the user confirms.

import { runtime } from 'raj'

runtime({
  init: [0], // State is an integer to count
  update (message, state) {
    return [state + 1] // Increment the state
  },
  view (state, dispatch) {
    const keepCounting = window.confirm(`Count is ${state}. Increment?`)
    if (keepCounting) {
      dispatch()
    }
  }
})

Note: Raj is view layer agnostic. Here we use the browser's built-in view to play the part.

Architecture

Raj applications are structured as programs.

Every program begins with an initial state, which can be anything, and an optional effect. These are put into an array which is the init property of the program.

const init = [initialState, /* optional */ initialEffect]

"Effects" are functions which receive a function dispatch. Effects handle asynchronous work like data-fetching, timers, and managing event listeners. They can pass dispatch messages and Raj uses those to update the state.

function effect (dispatch) {
  // do anything or nothing; preferably something asynchronous
  // call dispatch 0, 1, or N times
  dispatch(message)
}

A "message" can be anything; a server response, the current time, even undefined.

When a message is dispatched, Raj passes that message and the current state to update. The update function returns a new state and optional effect. The business logic of the program is handled with this function.

function update (message, currentState) {
  return [newState, /* optional */ effect]
}

The view is a special effect that receives both the current state and the dispatch function. The view can return anything. For the React view layer, the view returns React elements to be rendered.

function view (currentState, dispatch) {
  // anything, depending on choice of view library
}

The init, update, and view form a "program" which is just an object with those properties:

const program = {
  init: [initialState, /* optional */ initialEffect],
  update (message, currentState) {
    return [newState, /* optional */ effect]
  },
  view (currentState, dispatch) {
    // anything, depending on choice of view library
  }
};

Building any program follows the same steps:

  1. Define the initial state and effect with init
  2. Define the state transitions and effects with update(message, state)
  3. Define the view with view(state, dispatch)
  4. Tie it all together into a program

Programs compose, so a parent program might contain child programs.

In this way, programs most often compose into a tree structure.

The root program is passed to Raj's runtime. The runtime calls the program, manages its state, and runs its effects.

import { runtime } from 'raj'
import { program } from './app'

runtime(program)

The Raj by Example documentation covers this in greater detail.