{"id":13510306,"url":"https://github.com/andrejewski/raj","last_synced_at":"2025-07-12T19:37:42.537Z","repository":{"id":68511768,"uuid":"94049827","full_name":"andrejewski/raj","owner":"andrejewski","description":"The Elm Architecture for JavaScript","archived":false,"fork":false,"pushed_at":"2020-05-11T17:28:58.000Z","size":141,"stargazers_count":198,"open_issues_count":9,"forks_count":8,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-06-28T17:10:17.108Z","etag":null,"topics":["effects","framework","message","runtime"],"latest_commit_sha":null,"homepage":"https://jew.ski/raj","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andrejewski.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-06-12T03:00:48.000Z","updated_at":"2025-06-19T05:35:16.000Z","dependencies_parsed_at":"2023-03-11T03:48:58.814Z","dependency_job_id":null,"html_url":"https://github.com/andrejewski/raj","commit_stats":{"total_commits":57,"total_committers":2,"mean_commits":28.5,"dds":0.08771929824561409,"last_synced_commit":"a5e351f7d46e95a0ed26e505fc02a82d4880226e"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/andrejewski/raj","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrejewski%2Fraj","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrejewski%2Fraj/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrejewski%2Fraj/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrejewski%2Fraj/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andrejewski","download_url":"https://codeload.github.com/andrejewski/raj/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrejewski%2Fraj/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265044259,"owners_count":23702906,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["effects","framework","message","runtime"],"created_at":"2024-08-01T02:01:32.989Z","updated_at":"2025-07-12T19:37:42.480Z","avatar_url":"https://github.com/andrejewski.png","language":"JavaScript","readme":"\u003ch1 align=\"center\"\u003e\n\t\u003cimg width=\"320\" src=\"docs/raj.svg\" alt=\"Raj\"\u003e\n  \u003cbr\u003e\n  \u003cbr\u003e\n\u003c/h1\u003e\n\n\u003e The Elm Architecture for JavaScript\n\n```sh\nnpm install raj\n```\n\n[![npm](https://img.shields.io/npm/v/raj.svg)](https://www.npmjs.com/package/raj)\n[![Build Status](https://travis-ci.org/andrejewski/raj.svg?branch=master)](https://travis-ci.org/andrejewski/raj)\n[![Greenkeeper badge](https://badges.greenkeeper.io/andrejewski/raj.svg)](https://greenkeeper.io/)\n\n## Features\n\n- **Understandable**\n  \u003cbr\u003eRaj is 34 lines; 190 bytes minified. This framework can fit in your head or even a tweet.\n\n- **Testable**\n  \u003cbr\u003eRaj forces us to design for better separated concerns, simpler logic, and easier tests.\n\n- **Minimal**\n  \u003cbr\u003eRaj provides a tiny foundation for libraries and applications.\n\n- **Portable**\n  \u003cbr\u003eRaj is view layer agnostic. The view is a side effect of state.\n\nCheck out the [homepage](https://jew.ski/raj/) for resources and ecosystem packages.\n\n## Example\nA counter that increments by one every time the user confirms.\n\n```js\nimport { runtime } from 'raj'\n\nruntime({\n  init: [0], // State is an integer to count\n  update (message, state) {\n    return [state + 1] // Increment the state\n  },\n  view (state, dispatch) {\n    const keepCounting = window.confirm(`Count is ${state}. Increment?`)\n    if (keepCounting) {\n      dispatch()\n    }\n  }\n})\n```\n\n*Note:* Raj is view layer agnostic.\nHere we use the browser's built-in view to play the part.\n\n## Architecture\n\nRaj applications are structured as programs.\n\nEvery program begins with an initial state, which can be anything, and an optional effect.\nThese are put into an array which is the `init` property of the program.\n\n```js\nconst init = [initialState, /* optional */ initialEffect]\n```\n\n\"Effects\" are functions which receive a function `dispatch`.\nEffects handle asynchronous work like data-fetching, timers, and managing event listeners.\nThey can pass `dispatch` messages and Raj uses those to update the state.\n\n```js\nfunction effect (dispatch) {\n  // do anything or nothing; preferably something asynchronous\n  // call dispatch 0, 1, or N times\n  dispatch(message)\n}\n```\n\nA \"message\" can be anything; a server response, the current time, even `undefined`.\n\nWhen a message is dispatched, Raj passes that message and the current state to `update`.\nThe `update` function returns a new state and optional effect.\nThe business logic of the program is handled with this function.\n\n```js\nfunction update (message, currentState) {\n  return [newState, /* optional */ effect]\n}\n```\n\nThe `view` is a special effect that receives both the current state and the `dispatch` function.\nThe `view` can return anything.\nFor the [React view layer](https://github.com/andrejewski/raj-react), the `view` returns React elements to be rendered.\n\n```js\nfunction view (currentState, dispatch) {\n  // anything, depending on choice of view library\n}\n```\n\nThe `init`, `update`, and `view` form a \"program\" which is just an object with those properties:\n\n```js\nconst program = {\n  init: [initialState, /* optional */ initialEffect],\n  update (message, currentState) {\n    return [newState, /* optional */ effect]\n  },\n  view (currentState, dispatch) {\n    // anything, depending on choice of view library\n  }\n};\n```\n\nBuilding any program follows the same steps:\n\n1. Define the initial state and effect with `init`\n1. Define the state transitions and effects with `update(message, state)`\n1. Define the view with `view(state, dispatch)`\n1. Tie it all together into a `program`\n\nPrograms compose, so a parent program might contain child programs.\n\n- The parent's `init` may contain the child's `init`.\n- The parent's `update` may call the child's `update` with messages for the child and the child's state.\n- The parent's `view` may call the child's `view` with the child's state and `dispatch`.\n\nIn this way, programs most often compose into a tree structure.\n\nThe root program is passed to Raj's `runtime`.\nThe runtime calls the program, manages its state, and runs its effects.\n\n```js\nimport { runtime } from 'raj'\nimport { program } from './app'\n\nruntime(program)\n```\n\nThe [Raj by Example](https://github.com/andrejewski/raj-by-example) documentation covers this in greater detail.\n","funding_links":[],"categories":["JavaScript","framework"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrejewski%2Fraj","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandrejewski%2Fraj","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrejewski%2Fraj/lists"}