{"id":43770197,"url":"https://github.com/cesbit/vlow","last_synced_at":"2026-02-05T16:34:33.793Z","repository":{"id":42237651,"uuid":"135767873","full_name":"cesbit/vlow","owner":"cesbit","description":"A simple library for unidirectional dataflow architecture inspired by Reflux","archived":false,"fork":false,"pushed_at":"2025-10-15T07:50:15.000Z","size":1235,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-10-25T10:08:43.064Z","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":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cesbit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"cesbit"}},"created_at":"2018-06-01T22:15:18.000Z","updated_at":"2025-10-15T07:50:01.000Z","dependencies_parsed_at":"2023-02-01T04:46:04.480Z","dependency_job_id":"cfa5cb90-7883-4a56-acd9-978f5e90ff2a","html_url":"https://github.com/cesbit/vlow","commit_stats":{"total_commits":86,"total_committers":4,"mean_commits":21.5,"dds":0.313953488372093,"last_synced_commit":"5dabe49c11808070a7ab4ee75a0cff1f49510b37"},"previous_names":["transceptor-technology/vlow"],"tags_count":31,"template":false,"template_full_name":null,"purl":"pkg:github/cesbit/vlow","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesbit%2Fvlow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesbit%2Fvlow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesbit%2Fvlow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesbit%2Fvlow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cesbit","download_url":"https://codeload.github.com/cesbit/vlow/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesbit%2Fvlow/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29125878,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-05T14:05:12.718Z","status":"ssl_error","status_checked_at":"2026-02-05T14:03:53.078Z","response_time":65,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":"2026-02-05T16:34:33.120Z","updated_at":"2026-02-05T16:34:33.786Z","avatar_url":"https://github.com/cesbit.png","language":"JavaScript","funding_links":["https://github.com/sponsors/cesbit"],"categories":[],"sub_categories":[],"readme":"[![CI](https://github.com/cesbit/vlow/workflows/CI/badge.svg)](https://github.com/cesbit/vlow/actions)\n[![Release Version](https://img.shields.io/github/release/cesbit/vlow)](https://github.com/cesbit/vlow/releases)\n\n# Vlow\n\nA simple library for unidirectional dataflow architecture inspired by Reflux\n\n---------------------------------------\n  * [Installation](#installation)\n  * [Overview](#overview)\n  * [Create actions](#create-actions)\n  * [Create a store](#create-a-store)\n  * [Map stores to Components](#map-stores-to-components)\n    * [Using withVlow](#using-withvlow)\n    * [Using Vlow Component](#using-vlow-component)\n        * [Alternative super class](#alternative-super-class)\n    * [Using altState](#using-altstate)\n    * [No more listeners](#no-more-listeners)\n  * [TypeScript Store and Actions](#use-typescript)\n\n---------------------------------------\n\n## Installation\nUsing npm:\n\n```\n$ npm i vlow\n```\n\nIn your project:\n\n```javascript\nimport Vlow from 'vlow';\n// Exposes:\n//  - Vlow.version\n//  - Vlow.createActions\n//  - Vlow.factoryActions\n//  - Vlow.Store\n//  - Vlow.Component\n//  - Vlow.withVlow\n```\n\nOr... download the latest release from [here](https://github.com/cesbit/vlow/releases/latest) and load the file in inside your project.\nFor example:\n```html\n\u003c!-- Add this line to expose `window.vlow.default` --\u003e\n\u003c!-- WARN: Make sure React is loaded before this line --\u003e\n\u003cscript src=\"vlow.min.js\"\u003e\u003c/script\u003e\n```\n\n## Overview\nVlow uses **actions** to update one or more **stores** which updates the state\nof all **components** who are mapped to the store(s). In turn, a component\ntriggers an action. Vlow can be used for keeping a global state.\n\nThere are three steps which need to be understood to use Vlow:\n1. [Create Actions](#create-actions)\n2. [Create Stores](#create-a-store)\n3. [Map store(s) to Components](#map-stores-to-components)\n\n## Create actions\nActions can be created using the `Vlow.createActions` function:\n```javascript\n// this example creates an add and remove action\nconst ItemActions = Vlow.createActions([\n    'add',\n    'remove',\n]);\n```\n\nInvoking an action is as simple as calling the function, for example:\n```javascript\nItemsActions.add(item);\n```\n\n## Create a store\nA Vlow Store is an object which holds a global state which can be shared across\ncomponents.\n\nCreating a store can be done by creating a subclass of `Vlow.Store` and call\nthe Store constructor with an actions object, for example:\n```javascript\nclass ItemStore extends Vlow.Store {\n    constructor() {\n        // Call super with the actions to which this store should\n        // listen too.\n        // Note: multiple actions instances are possible,\n        //       for example super(Actions1, Actions2);\n        super(ItemActions);\n\n        // Create the initial state\n        this.state = {\n            items: []\n        };\n    }\n\n    // Implement onAction functions for each action defined by actions.\n    // It is not required to create functions for all actions but usually\n    // this is what you want and Vlow logs a warning in `development` mode\n    // when actions are not implemented.\n    onAdd(item) {\n        // Update the state like you would do with React.\n        // Just like react the first argument can also be a function.\n        //\n        // An optional second argument can be used. When given it must be\n        // a callback function() which will be called once when all\n        // components which are mapped to the store are rendered.\n        this.setState({items: [...this.state.items, item]});\n    }\n\n    onRemove(itemId) {\n        this.setState({items: this.state.filter(i =\u003e i.id !== itemId)});\n    }\n}\n```\n\n## Map stores to Components\nNow that the actions and stores are created, it is time to map them to a\ncomponent.\n\nThis can be done either by using `Vlow.withVlow` which is the preferred method\nas of version 1.1.0, or it can be done by extending the `Vlow.Component` class.\n\n### Using withVlow\nBy using `withVlow` the store will be mapped to the component props.\nThe function `withVlow` requires a Vlow Store or an array with multiple stores\nand returns a new function which accepts a component you want to wrap.\n\nHere are some valid examples:\n\n```javascript\n// Just parse the store\nwithVlow(SomeStore)(MyComponent);\n\n// Multiple stores\nwithVlow([SomeStore, SomeOtherStore])(MyComponent);\n\n// Map only specific store keys\nwithVlow({\n    store: ItemStore,\n    keys: ['items'] // listen only to 'items' changes\n})(MyComponent);\n```\n\nAnd this is an example of how `withVlow` can be used:\n```javascript\nimport {withVlow} from 'vlow';\nimport ItemStore from '../Stores/ItemStore';\n\nconst ItemComponent = ({items}) =\u003e (\n    \u003cul\u003e\n        {items.map(i =\u003e \u003cli key={i.id}\u003e{i.text}\u003c/li\u003e)}\n    \u003c/ul\u003e\n)\n\nexport default withVlow(ItemStore)(ItemComponent);\n```\n\n\u003eNote: It is still ok to use `PropTypes` for checking the props from a store,\n\u003efor example:\n\u003e```javascript\n\u003eItemComponent.propTypes = {\n\u003e    items: PropTypes.arrayOf(PropTypes.shape({\n\u003e        id: PropTypes.number,\n\u003e        text: PropTypes.string\n\u003e    })).isRequired\n\u003e};\n\u003e```\n\n### Using Vlow Component\nIt is recommended to use [withVlow](#using-withvlow) instead of `Vlow.Component`\nbut in some cases you might prefer to extend your component directly with a `Vlow.Component` instead of `React.Component`.\nThe main difference is that the *state* from the store will be merged with your\ncomponents state, instead of receiving the *state* by props.\n\nInside the `constructor` you should use the `mapStore()` or\n`mapStores()` function to map the state to the store.\n\nHere is an example of how to use `Vlow.Component`:\n\n```javascript\nclass ItemComponent extends Vlow.Component {\n    constructor(props) {\n        super(props);\n        // In case you want to set state in the constructor, make\n        // sure to do this before calling mapStore() since you\n        // otherwise would overwrite the state defined by the store.\n        this.state = {\n            some: 'state'\n        };\n\n        // Function mapStore() accepts a store in which case the\n        // complete store state will be mapped to the components state.\n        // There are two more options:\n        //\n        // - Using a keys filter in which case a component only listens\n        //   to certain store changes.\n        //\n        //      this.mapStore({\n        //          store: ItemStore,\n        //          keys: ['items'] // listen only to 'items' changes,\n        //                          // other store state will be ignored\n        //      });\n        //\n        // - Using an altState function which allows you to modify state\n        //   before it will be applied. (more info on altState() can be\n        //   found later in this documentation)\n        this.mapStore(ItemStore);\n\n        // The state now looks like:\n        //    {some: 'state', items: []}\n        // It's ok to modify the state as long as you do not\n        // overwrite `this.state` with a new Object, for example:\n        this.state.hasItems = this.state.items.length \u003e 0;\n    }\n\n    render() {\n        return (\n            \u003cul\u003e\n                {this.state.items.map(i =\u003e \u003cli key={i.id}\u003e{i.text}\u003c/li\u003e)}\n            \u003c/ul\u003e\n        );\n    }\n}\n```\n\nIn case you need multiple stores, the function `this.mapStores([])` can be used\nwhich accepts an Array of stores. Each store may be defined in a different way.\n```javascript\nthis.mapStores([\n    StoreOne, {\n        store: StoreTwo\n    }, {\n        store: StoreThree,\n        keys: ['foo', 'status']\n    }, {\n        store: StoreFour,\n        altState: storeState, state, props =\u003e storeState\n    }\n]);\n```\n\n\n#### Alternative super class\nBy default the `Vlow.Component` class extends the `React.Component` class but\nyou might want `Vlow.Component` to extend your own custom class. This is\npossible by using `Vlow.Component.extend()`.\n\n```javascript\n// In this example we create a Vlow Component which extends\n// React.PureComponent instead of the default React.Component\nclass MyComponent extends Vlow.Component.extend(React.PureComponent) {\n    ...\n}\n```\n\n### Using altState\nSometimes you want to listen to state changes in a store but then do something\nwith this state instead of just applying the state to a component.\nThis can be done by using an `altState(storeState, state, props)` hook which\nwill be triggered on state changes in the store but *before* the component state\nis changed. The `altState` function should return the state changes you want to\nmake or `null` in case you don't want to update the state of the component.\n```javascript\nfunction altState(storeState, state, props) {\n    // This function should return the state\n    // you want to apply on the component. The function can\n    // also return `null` in which case the components state\n    // will not be changed.\n    if (props.status === 'error') {\n        // the components state will not be changed\n        return null;\n    }\n    // Return some alternative state for `this` component.\n    // Other components still receive the `original` state\n    // from the store.\n    return {\n        items: storeState.items.filter(i =\u003e i.age \u003e state.minAge)\n    };\n}\n\n// Use the altState function\nconst stores = {\n    store: MyStore,\n    altState,\n};\n```\n\n### No more listeners\nIf there are no components left who listen to the store, the store function `listenersEmpty()` is called.\nBy default, this function does nothing but you might implement it yourself and overwrite the default behavior.\nFor example, you might want to unregister the store if no more components are listening to clean-up memory:\n\n```javascript\nimport Vlow from 'vlow';\n\n// define the state on the store, e.g. this.state.todos\nexport interface IMyStore {\n    todos: string[];\n}\n\nclass MyStore extends Vlow.Store\u003cIMyStore\u003e {\n\n    listenersEmpty() {\n        this.unregisterStore();  // the store will unregister itself from the\n                                 // actions until a new store is created\n    }\n}\n```\n\n## Use TypeScript\n\nWith Vlow, it is possible to use TypeScript and have both the state in your store and the actions typed.\n\nExample:\n\n```javascript\nimport Vlow from 'vlow';\n\n// define the state on the store, e.g. this.state.todos\nexport interface IMyStore {\n    todos: string[];\n}\n\nclass MyStore extends Vlow.Store\u003cIMyStore\u003e {\n    onFetch(limit: number) { /* fetch todo's... */ }\n}\n\nconst actions = [\n    'fetch',\n] as const;\nconst MyActions = Vlow.factoryActions\u003cMyStore\u003e()(actions);\n// MyActions.fetch(10); understands the arguments of the `onFetch` defined in the store\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcesbit%2Fvlow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcesbit%2Fvlow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcesbit%2Fvlow/lists"}