{"id":17038055,"url":"https://github.com/modesty/snow-flux","last_synced_at":"2026-05-13T05:32:38.175Z","repository":{"id":57364754,"uuid":"50265951","full_name":"modesty/snow-flux","owner":"modesty","description":"A simple and practical unidirectional data flow implementation with Reactive Extensions RxJS.","archived":false,"fork":false,"pushed_at":"2023-11-12T02:07:29.000Z","size":13,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-28T21:59:11.490Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/modesty.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":"2016-01-24T00:46:59.000Z","updated_at":"2023-11-12T02:07:33.000Z","dependencies_parsed_at":"2024-11-29T15:33:09.578Z","dependency_job_id":null,"html_url":"https://github.com/modesty/snow-flux","commit_stats":{"total_commits":10,"total_committers":1,"mean_commits":10.0,"dds":0.0,"last_synced_commit":"af3f8f259f0c6d0ef38389304a9fa5ca5b1f16db"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/modesty%2Fsnow-flux","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/modesty%2Fsnow-flux/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/modesty%2Fsnow-flux/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/modesty%2Fsnow-flux/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/modesty","download_url":"https://codeload.github.com/modesty/snow-flux/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245032958,"owners_count":20550174,"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":[],"created_at":"2024-10-14T08:55:51.760Z","updated_at":"2026-05-13T05:32:38.144Z","avatar_url":"https://github.com/modesty.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Snow-Flux\n\n\u003e A simple and practical unidirectional data flow implementation with Reactive Extensions [RxJS](https://github.com/Reactive-Extensions/RxJS).\n\nThis module is utilizing the expressiveness and conciseness of [RxJS](https://github.com/Reactive-Extensions/RxJS) to simplify and empower of the idea of unidirectional data flow, enabling the 'store' to be the single source of truth for component state in [ReactJS] (https://github.com/facebook/react) based web application with greater simplicity and effectiveness. More in depth discussion can be found at [Reactive Flux without Flux](http://www.codeproject.com/Articles/1063098/Reactive-Flux-without-Flux).\n\n## Installation\n\nInstall from npm:\n```\nnpm install snow-flux\n```\n\nOr, install from GitHub:\n```\nnpm install modesty/snow-flux\n```\n\nThen, build 'dist' as needed:\n```\nnpm run gulp\n```\n\n## Why Snow-Flux\n\nThere are other [RxJS](https://github.com/Reactive-Extensions/RxJS) based Flux implementations in GitHub, [Reactive Flux without Flux](http://www.codeproject.com/Articles/1063098/Reactive-Flux-without-Flux) lists at least 5 in 'Overview' section. I'm building this module with the following goals and features:\n\n* Managed RxJS decencies: RxJS is a big library: complete, main, lite, core, etc., we’d like to manage the dependencies to the bare minimum. In the meantime, the dependency list can grow if the application uses more Rx features\n* Avoid [waitFor](https://github.com/facebook/flux/issues/209) in Action while make Action type extensible\n* Enable external handler to subscribe to Action through Store: this is to enable Store to play well with legacy code, like a scoped function within Angular controller\n* Pair an Action with a Store by default, while still enable Store to subscribe to multiple Actions\n* Eliminating global dispatcher and singleton, keep the base implementation practical and simple\n* Promote immutable data structure by __build-in redo/undo__ functionality in Store, but not enforce it, concrete instance of Store can opt-in for undo/redo support\n* No addition concepts and constructs beyond Flux, keep everything simple\n\n## About Store and Action\n\nHere are some general technical considerations for snow-flux:\n\n* Store data object is private, use [React Immutable Helper](https://facebook.github.io/react/docs/update.html) or [Immutable.js](https://github.com/facebook/immutable-js) to manipulate and keep it immutable, undo/redo can opt-in or opt-out any moment\n* Action _types_ will be ready only properties and only customizable when instantiate\n* Both Store and Action are backed by a [BehaviorSubject](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/subjects/behaviorsubject.md), it makes Store and Action are both [observable](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/observable.md) and [observer](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/observer.md), and also makes sure the observer will always get the initial or last data regardless the timing to subscribe\n* Subscribe and dispose invocation can be reentrant\n* All other Flux architectural aspects stay, including Store can subscribe to multiple Action, view can subscribe to multiple stores, etc., although the default behavior prefers one to one relationship for simplicity\n\n## Examples\n\n### Actions\n#### Create a simple Action:\n\n```javascript\n'use strict';\n\nimport { SfAction } from 'snow-flux';\n\nlet NavBarAction = new SfAction({\n\tACTION: \"NAV_BAR_ACTION\", UNDO_REDO: \"NAV_BAR_UNDO_REDO\", REFRESH_APP: \"REFRESH_APP\"\n});\n\nmodule.exports = NavBarAction;\n```\n\n#### Create an Action with customized initialization method\n```javascript\n'use strict';\n\nimport { SfAction } from 'snow-flux';\n\nlet PermAction = new SfAction({\n\tACTION: \"USER_ACTION\", UNDO_REDO: \"USER_UNDO_REDO\",\n\tUPDATE_ONE_RIGHT: \"UPDATE_ONE_RIGHT\",\n\tUPDATE_ALL_PERM: \"UPDATE_ALL_PERM\", UPDATE_ONE_PERM: \"UPDATE_ONE_PERM\"\n}, {\n\tinit(httpRequest, scopeId) {\n\t\tlet getAppEndpoint =  \"api/now/delegation/permission/list\";\n\t\treturn httpRequest.get(getAppEndpoint).then(\n\t\t\tresponse =\u003e response.data.result\n\t\t);\n\t}\n});\n\nmodule.exports = PermAction;\n```\n\n#### Dispatch an Action from React component:\n\n```javascript\n\trenderLinkItems() {\n\t\treturn this.props.links.map( (item, idx) =\u003e {\n\t\t\tlet clsName = (this.props.align === 'left' \u0026\u0026 idx === 0) ? \"btn btn-primary\" : \"icon-link-hover-handler\";\n\n\t\t\treturn (\n\t\t\t\t\u003cli key={item.action} \u003e\n\t\t\t\t\t\u003cdiv className={clsName} onClick={this.onAppLinksAction.bind(this, idx)}\u003e\n\t\t\t\t\t\t\u003ca href=\"#\"\u003e\n\t\t\t\t\t\t\t\u003ci className={\"icon \" + item.icon}\u003e\u003c/i\u003e\u003cspan\u003e \u003c/span\u003e{item.t_label}\n\t\t\t\t\t\t\u003c/a\u003e\n\t\t\t\t\t\u003c/div\u003e\n\t\t\t\t\u003c/li\u003e\n\t\t\t);\n\t\t});\n\t},\n\n\tonAppLinksAction(idx, evt) {\n\t\tevt.preventDefault();\n\t\tlet actName = this.props.links[idx].action;\n\t\tnavBarAction.dispatch(navBarAction.ACTION, actName);\n\t}\n```\n\n### Store\n#### Createa store with [React Immutable Helper](https://facebook.github.io/react/docs/update.html) to localize all \"t_label\" properties when initializes:\n\n```javascript\n'use strict';\n\nimport reactUpdate from 'react/lib/update';\nimport { SfStore } from 'snow-flux';\nimport navBarAction from './navBarAction';\n\nlet NavBarStore = new SfStore({\n\t\tfavorites: [\n\t\t\t{t_label: \"Create New\", icon: \"icon-add\", action: \"modal-createNew\"}\n\t\t],\n\t\tsearches: [\n\t\t\t{t_label: \"Go To\", icon: \"icon-search\", action: \"modal-goto\"},\n\t\t\t{t_label: \"Search\", icon: \"icon-advanced-search\", action: \"modal-search\"}\n\t\t]\n\t}, \n\tnavBarAction, {\n\t\tinit(i18nFunc) {\n\t\t\t// imperative initialization with i18n\n\t\t\tfunction _translate(itemArray) {\n\t\t\t\treturn itemArray.map((item, idx, array) =\u003e {\n\t\t\t\t\treturn reactUpdate(item, {\n\t\t\t\t\t\tlabel: {$set: i18nFunc(item.t_label)}\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthis._storeState = reactUpdate(this._storeState, {\n\t\t\t\tfavorites: {\n\t\t\t\t\t$apply: _translate\n\t\t\t\t},\n\t\t\t\tsearches: {\n\t\t\t\t\t$apply: _translate\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tthis.streamChange();\n\t\t}\n\t}\n);\n\nmodule.exports = NavBarStore;\n```\n\n\n#### Create a store with Action handlers:\n\n```javascript\n'use strict';\n\nimport reactUpdate from 'react/lib/update';\nimport { SfStore } from 'snow-flux';\nimport navBarAction from './navBarAction';\n\nlet NavBarStore = new SfStore({\n\t\tfavorites: [\n\t\t\t{t_label: \"Create New\", icon: \"icon-add\", action: \"modal-createNew\"}\n\t\t],\n\t\tsearches: [\n\t\t\t{t_label: \"Go To\", icon: \"icon-search\", action: \"modal-goto\"},\n\t\t\t{t_label: \"Search\", icon: \"icon-advanced-search\", action: \"modal-search\"}\n\t\t]\n\t}, \n\tnavBarAction, {\n\t\tinit(i18nFunc) {\n\t\t\t// imperative initialization with i18n\n\t\t\tfunction _translate(itemArray) {\n\t\t\t\treturn itemArray.map((item, idx, array) =\u003e {\n\t\t\t\t\treturn reactUpdate(item, {\n\t\t\t\t\t\tlabel: {$set: i18nFunc(item.t_label)}\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthis._storeState = reactUpdate(this._storeState, {\n\t\t\t\tfavorites: { $apply: _translate },\n\t\t\t\tsearches: { $apply: _translate }\n\t\t\t});\n\n\t\t\tthis.registerAction(this.action, 'REFRESH_APP', this.onRefreshApp);\n\n\t\t\tthis.streamChange();\n\t\t},\n\t\tonRefreshApp(action) {\n\t\t\tthis.resetStoreState();\n\t\t}\n\t}\n);\n\nmodule.exports = NavBarStore;\n```\n\n#### Subscribe to store changes in top level (container component / higher order component / controller component) React component:\n\n```javascript\n\t...\n\tcomponentDidMount() {\n\t\tthis.stateSubs = navBarStore.subscribe( (stateData) =\u003e this.setState(stateData) );\n\t},\n\n\tcomponentWillUnmount() {\n\t\tnavBarStore.dispose(this.stateSubs);\n\t},\n\t...\n```\n\n## More info\n\nMore in depth discussion can be found at [Reactive Flux without Flux](http://www.codeproject.com/Articles/1063098/Reactive-Flux-without-Flux).\n\n## Contribution\n\nBy participating in this project, you are expected to honor this [code of conduct](http://todogroup.org/opencodeofconduct/#Open+Code+of+Conduct/abuse@todogroup.org).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmodesty%2Fsnow-flux","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmodesty%2Fsnow-flux","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmodesty%2Fsnow-flux/lists"}