{"id":20315169,"url":"https://github.com/ipluser/react-flux-demo","last_synced_at":"2026-04-17T13:06:27.935Z","repository":{"id":86726769,"uuid":"58808828","full_name":"ipluser/react-flux-demo","owner":"ipluser","description":"An learning demo that is flux application architecture.","archived":false,"fork":false,"pushed_at":"2017-03-30T15:26:32.000Z","size":35,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-14T12:51:33.619Z","etag":null,"topics":["data-flow","flux","flux-application","flux-application-architecture","flux-architecture","react","react-flux"],"latest_commit_sha":null,"homepage":"https://github.com/ipluser/react-flux-demo","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/ipluser.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-05-14T13:19:36.000Z","updated_at":"2023-03-10T09:54:21.000Z","dependencies_parsed_at":"2023-03-04T07:45:51.877Z","dependency_job_id":null,"html_url":"https://github.com/ipluser/react-flux-demo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ipluser%2Freact-flux-demo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ipluser%2Freact-flux-demo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ipluser%2Freact-flux-demo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ipluser%2Freact-flux-demo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ipluser","download_url":"https://codeload.github.com/ipluser/react-flux-demo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241818881,"owners_count":20025210,"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":["data-flow","flux","flux-application","flux-application-architecture","flux-architecture","react","react-flux"],"created_at":"2024-11-14T18:18:12.389Z","updated_at":"2026-04-17T13:06:22.915Z","avatar_url":"https://github.com/ipluser.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# react-flux-demo\nAn learning demo that is flux application architecture.\n\n**Note**: [中文版](README_CN.md)\n\n## Quick Start\n```bash\n$ git clone https://github.com/ipluser/react-flux-demo.git\n$ cd react-flux-demo\n$ npm install\n$ npm start\n```\n\nThe browser will auto to open a new tab, if not, please visit `http://127.0.0.1:8080`:\n\n![Demo](public/img/flux__demo.png)\n\n## Core Concepts\nFlux applications have four major parts: the dispatcher, the stores, the views, and the actions. \n\n| Name | Description |\n|:-----|:------------|\n| Views | React components |\n| Actions | Behavior and action of Views, e.g. `click event` |\n| Dispatcher | Register actions, receive actions and calling callback of data flow |\n| Stores | Managing the Application's state and broadcast an event declaring for Views that their state has changed |\n\n![Flux Data Flow](public/img/flux__data-flow.png)\n\nA unidirectional data flow is central to the Flux pattern. The dispatcher, stores and views are independent nodes with distinct inputs and outputs. The actions are simple objects containing the new data and an identifying type property.\n\n## Demo Explaination\n### Views\nOpen the entry file ***main.jsx***:\n\n```js\n// public/scripts/main.jsx\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport TodoController from './components/todoController.jsx';\n\nReactDOM.render(\u003cTodoController /\u003e, document.body);\n```\n\nThe above code use [ReactJS Controller View Pattern](http://blog.andrewray.me/the-reactjs-controller-view-pattern/)，a `controller view` is a top level component that holds all state and passes it to children as props. Let's see ***todoController.jsx***:\n\n```js\n// public/scripts/components/todoController.jsx\nimport React from 'react';\n\nimport TodoAction from '../actions/todoAction.js';\nimport TodoStore from '../stores/todoStore.js';\nimport Todo from './todo.jsx';\n\nexport default class TodoController extends React.Component {\n  constructor(props) {\n    super(props);\n  }\n\n  newItem() {\n    TodoAction.addItem('new item');\n  }\n\n  render() {\n    return \u003cTodo newItem={this.newItem} /\u003e;\n  }\n}\n```\n\nIn above code, the **TodoController** just assign action for **Todo** component. The **Todo** receive props and render:\n\n```js\n// public/scripts/components/todo.jsx\nimport React from 'react';\n\nimport '../../styles/components/todo.scss';\n\nexport default function Todo(props) {\n  let list = props.items.map((item, index) =\u003e {\n    return \u003cli className=\"color--red\" key={index}\u003e{item}\u003c/li\u003e;\n  });\n\n  return (\n    \u003cdiv className=\"todo\"\u003e\n      \u003cul\u003e{list}\u003c/ul\u003e\n      \u003cbutton className=\"todo__click-btn\" onClick={props.newItem}\u003eTodo\u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\nOnce click **todo** button, The **TodoController** will trigger an **addItem** action.\n\n## Actions\nThe **TodoAction** carry data and *actionType* property to **Dispatcher** for dipatch data flow:\n\n```js\n// public/scripts/actions/todoAction.js\nimport AppDispatcher from '../dispatcher.js';\nimport TodoConstant from '../constants/todoConstant.js';\n\nclass TodoAction {\n  addItem(text) {\n    AppDispatcher.dispatch({\n      actionType: TodoConstant.ADD_ITEM,\n      text\n    });\n  }\n}\n\nexport default new TodoAction();\n```\n\nThe **todoConstant.js** is constant object that includes all actionType:\n\n```js\n// public/scripts/constants/todoConstant.js\nexport default {\n  ADD_ITEM: 'TODO_ADD_ITEM'\n};\n```\n\n## Dispatcher\nThe **Dispatcher** is the central hub that manages all data flow in a Flux application. Each **Store** registers itself and provides a callback:\n\n```js\n// public/scripts/dispatcher.js\nimport { Dispatcher } from 'flux';\n\nimport TodoStore from './stores/todoStore';\nimport TodoConstant from './constants/todoConstant';\n\nconst AppDispatcher = new Dispatcher();\n\nTodoStore.dispatchToken = AppDispatcher.register(payload =\u003e {\n  switch (payload.actionType) {\n    case TodoConstant.ADD_ITEM:\n      TodoStore.addItem(payload.text);\n      break;\n    default:\n  }\n});\n\nexport default AppDispatcher;\n```\n\nIn the above code, when **TodoAction** provides the dispatcher with a new action, the **TodoStore** receive the action via the callbacks in the registry.\n\n## Stores\nThe **TodoStore** contains state and logic. their role is somewhat similar to a *model* in a traditional MVC:\n\n```js\n// public/scripts/stores/todoStore.js\nimport EventEmitter from 'events';\n\nclass TodoStore extends EventEmitter {\n  constructor() {\n    super();\n    this.items = [];\n  }\n\n  getAll() {\n    return this.items;\n  }\n\n  addItem(text) {\n    this.items.push(text);\n    this.change();\n  }\n\n  change() {\n    this.emit('change');\n  }\n\n  addListener(name, callback) {\n    this.on(name, callback);\n  }\n\n  removeListener(name, callback) {\n    this.removeListener(name, callback);\n  }\n}\n\nexport default new TodoStore();\n```\n\nIn the above code, **TodoStore** will emit an event to the **Views** when the state is changed.\n\n## Views, again\nBack to **TodoController**, let it initialize application's state and listen the Store's change event:\n\n```js\n// public/scripts/components/todoController.jsx\nimport React from 'react';\n\nimport TodoAction from '../actions/todoAction.js';\nimport TodoStore from '../stores/todoStore.js';\nimport Todo from './todo.jsx';\n\nexport default class TodoController extends React.Component {\n  constructor(props) {\n    super(props);\n    this.state = { items: TodoStore.getAll() };\n    this.onListChange = this.onListChange.bind(this);\n  }\n\n  componentDidMount() {\n    TodoStore.addListener('change', this.onListChange);\n  }\n\n  componentWillUnmount() {\n    TodoStore.removeListener('change', this.onListChange);\n  }\n\n  onListChange() {\n    this.setState({\n      items: TodoStore.getAll()\n    });\n  }\n\n  newItem() {\n    TodoAction.addItem('new item');\n  }\n\n  render() {\n    return \u003cTodo items={this.state.items} newItem={this.newItem} /\u003e;\n  }\n}\n```\n\nOnce the **TodoController** receive the state is changed, then it will trigger **Todo** to re-render.\n\n## References\n- [Facebook Flux](https://facebook.github.io/flux/docs/overview.html)\n- [ReactJS Controller View Pattern](http://blog.andrewray.me/the-reactjs-controller-view-pattern/)\n- [ruanyf - Flux Guide](http://www.ruanyifeng.com/blog/2016/01/flux.html)\n\n## LICENSE\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fipluser%2Freact-flux-demo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fipluser%2Freact-flux-demo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fipluser%2Freact-flux-demo/lists"}