{"id":26690768,"url":"https://github.com/philpl/fluorine","last_synced_at":"2025-03-26T16:01:05.251Z","repository":{"id":57140584,"uuid":"47122841","full_name":"kitten/fluorine","owner":"kitten","description":"[UNMAINTAINED] Reactive state and side effect management for React using a single stream of actions","archived":true,"fork":false,"pushed_at":"2017-06-13T18:16:55.000Z","size":1128,"stargazers_count":286,"open_issues_count":25,"forks_count":13,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-19T17:40:41.480Z","etag":null,"topics":["dispatcher","fluorine","flux","react","rxjs","state-management"],"latest_commit_sha":null,"homepage":"https://fluorinejs.org/","language":"JavaScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kitten.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-11-30T14:11:15.000Z","updated_at":"2024-09-23T10:35:36.000Z","dependencies_parsed_at":"2022-09-05T08:21:44.424Z","dependency_job_id":null,"html_url":"https://github.com/kitten/fluorine","commit_stats":null,"previous_names":["philpl/fluorine"],"tags_count":63,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kitten%2Ffluorine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kitten%2Ffluorine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kitten%2Ffluorine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kitten%2Ffluorine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kitten","download_url":"https://codeload.github.com/kitten/fluorine/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245689494,"owners_count":20656416,"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":["dispatcher","fluorine","flux","react","rxjs","state-management"],"created_at":"2025-03-26T16:00:36.417Z","updated_at":"2025-03-26T16:01:05.244Z","avatar_url":"https://github.com/kitten.png","language":"JavaScript","readme":"\u003cp align=\"center\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/philpl/fluorine/master/docs/fluorine-flasky-2x.gif\" width=400\u003e\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n\u003cstrong\u003eFlexible state and side effect manager using \u003ca href=\"https://github.com/Reactive-Extensions/RxJS\"\u003eRxJS\u003c/a\u003e for \u003ca href=\"https://facebook.github.io/react/\"\u003eReact\u003c/a\u003e.\u003c/strong\u003e\n\u003cbr\u003e\u003cbr\u003e\n\u003ca href=\"https://travis-ci.org/philpl/fluorine\"\u003e\u003cimg src=\"https://img.shields.io/travis/philpl/fluorine/master.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://coveralls.io/github/philpl/fluorine\"\u003e\u003cimg src=\"https://img.shields.io/coveralls/philpl/fluorine/master.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://slack.fluorinejs.org/\"\u003e\u003cimg alt=\"Join Fluorine's Slack!\" src=\"https://slack.fluorinejs.org/badge.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://npmjs.com/package/fluorine-lib\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/fluorine-lib.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://npmjs.com/package/fluorine-lib\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/fluorine-lib.svg\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## About\n\nFluorine provides you with easy, reactive state and side effect management,\naccumulating stores from streams of actions and side effects.\n\nIt builds on the ideas of Redux, while preserving a Flux-like Dispatcher\nas the single source of truth.\n\n- Your stores are directly reduced from the dispatcher and actions are dispatched on it\n- Manage your side effect as Observables (\"Agendas\") with automatic rollbacks on error\n- Unopinionated and simple API with Middleware support\n\nThis is the ultimate way to use RxJS for state and side effect management!\n\n## [Documentation](https://fluorinejs.org)\n\n* [Getting Started](https://fluorinejs.org/getting-started/index.html)\n* [Concepts](https://fluorinejs.org/concepts/index.html)\n* [API Reference](https://fluorinejs.org/api/index.html)\n\n## Quick Intro\n\nThis is just a short example that quickly presents all features of the Dispatcher.\nIt is of course not representetive for how to use it in real React projects.\n\n```js\nimport { createDispatcher } from 'fluorine-lib'\nimport thunk from 'fluorine-lib/lib/middleware/thunk'\n\n/**\n * This is a reducer, a pure function with (state, action) =\u003e state signature.\n * It describes how an action transforms the state into the next state.\n *\n * The shape of the state is up to you: it can be a primitive, an array, an object,\n * or even an Immutable.js data structure. The only important part is that you should\n * not mutate the state object, but return a new object if the state changes.\n *\n * In this example, we use a `switch` statement and strings, but you can use a helper that\n * follows a different convention (such as function maps) if it makes sense for your project.\n */\nfunction counter(state = 0, action) {\n  switch (action.type) {\n  case 'INCREMENT':\n    return state + 1\n  case 'DECREMENT':\n    return state - 1\n  default:\n    return state\n  }\n}\n\n// Create a dispatcher which is our event stream\nconst dispatcher = createDispatcher({ logging: true }, [ thunk ])\n\n// This reduces the dispatcher event stream to a store. This is essentially an\n// RxJS Observable that emits the state of the store over time\nconst store = dispatcher.reduce(counter)\n\nstore.subscribe(x =\u003e {\n  console.log(x) // Your store's state\n})\n\n// Dispatch an action, a thunk, or a promise\n\ndispatcher.next({ type: 'INCREMENT' })\n\ndispatcher.next(next =\u003e {\n  next({ type: 'DECREMENT' })\n})\n\ndispatcher.next(new Promise((resolve, reject) =\u003e {\n  resolve({ type: 'INCREMENT' })\n}))\n\n// Agendas: Schedule a task, represented by an observable that emits actions\n// If the observable fails, then all its changes are reverted\n\nconst addIfFetchSucceeds = Observable\n  .of({ type: 'ADD' })\n  .concat(Observable\n    .of('/ping')\n    .flatMap(path =\u003e Observable.fromPromise(fetch(path))))\n\ndispatcher.next(addIfFetchSucceeds)\n```\n\nJust as in Flux we've got stores, actions and a dispatcher. The seperation of\nconcern is intact, while the dispatcher exclusively is the single source of truth.\n\nCompared to Redux we've got fully functional actions and stores as well, but the\nstate is handled fully reactively using RxJS. We can even use all of RxJS's\noperators.\n\nOn top of that we've got a new way of handling side effects: Agendas. This enables\nyou to schedule observables as streams of actions, which roll back all their changes\nif they fail. This makes it easy to design exceedingly complex side effects.\n\n## Fluorine-related Projects\n\n* [react-fluorine-boilerplate](https://github.com/philpl/react-fluorine-boilerplate):\n  A boilerplate that gets your started with React, Fluorine and Hot Reloading\n\n* [fluorine-orchestra](https://github.com/philpl/fluorine-orchestra):\n  A data orchestration library with dependency resolution using Immutable.js\n\n## Frequently Asked Questions\n\n### Why write another Flux library?\n\nThe goal of this project is to create a efficient but minimal library on top\nof RxJS that can preserve your previous (pure reducer) stores and actions, which\nyou would write for a Redux project as well, but give you even more power over\nthem.\n\nRedux is building on top of the known strengths of Flux by mixing it with more\nfunctional ideas, but without a tool like RxJS it fails to combine the\ndispatcher and stores. Fluorine doesn't need containers for stores as\nevery store can be reduced from the actions on the Dispatcher reactively.\n\nOn top of that Fluorine provides a new way to manage side effects, which is much\nmore powerful than plain thunks.\n\n### Why the name?\n\nFluorine is (chemically-speaking) the most *reactive* non-metal. As Fluorine\nembraces RxJS to bring even more advantages of reactive programming to React, it\nis a fitting name.\n\nFurthermore the latin verb *fluo* means \"flow\", which is a direct refernce\nto Flux and its unidirectional data-flow.\n\n## Used and Supported by\n\n\u003ctable border=\"0\"\u003e\n\n\u003ctr\u003e\n\u003ctd\u003e\u003cimg src=\"https://datawallet.io/img/logo.svg\" height=\"100px\"/\u003e\u003c/td\u003e\n\u003ctd valign=\"middle\"\u003e\u003ch4\u003e\u003ca href=\"https://datawallet.io\"\u003eDataWallet\u003c/a\u003e\u003c/h4\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\n\u003c/table\u003e\n\n## Thanks to\n\n* The ReactiveX team, all the RxJS developers and the ReactiveX community\n* Dan Abramov for Redux that is a big influence to Fluorine\n* The React team\n\n","funding_links":[],"categories":["Uncategorized","Code Design"],"sub_categories":["Uncategorized","Data Store"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphilpl%2Ffluorine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphilpl%2Ffluorine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphilpl%2Ffluorine/lists"}