The Elm Architecture for JavaScript
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
docs Make runtime the main module Jun 17, 2018
test Make runtime the main module Jun 17, 2018
.gitignore Ecosystem (#12) Sep 11, 2017
.travis.yml Ecosystem (#12) Sep 11, 2017
LICENSE Initial commit Jun 12, 2017
README.md Add features section Jun 21, 2018
index.js Make runtime the main module Jun 17, 2018
package.json 1.0.0 Jun 21, 2018

README.md

Raj

The Elm Architecture for JavaScript

npm install raj

npm Build Status Greenkeeper badge

Features

  • Understandable
    Raj is 34 lines; 190 bytes minified. This framework can fit in your head or even a tweet.

  • Testable
    Raj forces us to design for better separated concerns, simpler logic, and easier tests.

  • Minimal
    Raj provides a tiny foundation for libraries and applications.

  • Portable
    Raj is view layer agnostic. The view is a side effect of state.

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.

  • The parent's init may contain the child's init.
  • The parent's update may call the child's update with messages for the child and the child's state.
  • The parent's view may call the child's view with the child's state and dispatch.

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.