Skip to content

Latest commit

 

History

History
237 lines (180 loc) · 5.94 KB

README_CN.md

File metadata and controls

237 lines (180 loc) · 5.94 KB

react-flux-demo

关于Flux应用的学习例子。

快速入门

$ git clone https://github.com/ipluser/react-flux-demo.git
$ cd react-flux-demo
$ npm install
$ npm start

浏览器将会自动打开一个新的网页标签,如果没有打开,请直接访问 http://127.0.0.1:8080

Demo

核心概念

Flux应用主要分为四个主要的部分:ViewsActionsDispatcherStores

名称 描述
Views 视图层。
Actions 行为动作层,视图层触发的动作,例如click event
Dispatcher 分发中心,注册/接受动作,管理数据流向。
Stores 数据层,管理应用状态,广播通知Views状态发生改变。

Flux Data Flow

单向数据流是Flux应用的核心。DispatcherStoresViews是独立的输入和输出节点,而Action是一个包含数据和动作类型的简单对象。

解析实例

视图层

打开项目入口文件main.jsx

// public/scripts/main.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import TodoController from './components/todoController.jsx';

ReactDOM.render(<TodoController />, document.body);

此处代码中采用了ReactJS Controller View模式,一个Controller View是应用中最顶层的组件,它管理着所有应用状态,并以属性方式传递给子组件。接下来我们看看todoController.jsx

// public/scripts/components/todoController.jsx
import React from 'react';

import TodoAction from '../actions/todoAction.js';
import TodoStore from '../stores/todoStore.js';
import Todo from './todo.jsx';

export default class TodoController extends React.Component {
  constructor(props) {
    super(props);
  }

  newItem() {
    TodoAction.addItem('new item');
  }

  render() {
    return <Todo newItem={this.newItem} />;
  }
}

正如你所看到的,TodoController仅仅只给Todo指定了动作。Todo组件接收属性和渲染:

// public/scripts/components/todo.jsx
import React from 'react';

import '../../styles/components/todo.scss';

export default function Todo(props) {
  let list = props.items.map((item, index) => {
    return <li className="color--red" key={index}>{item}</li>;
  });

  return (
    <div className="todo">
      <ul>{list}</ul>
      <button className="todo__click-btn" onClick={props.newItem}>Todo</button>
    </div>
  );
}

一旦点击todo按钮,TodoController将会触发addItem动作。

行为动作层

TodoAction将数据和动作类型传递给Dispatcher去分发数据流:

// public/scripts/actions/todoAction.js
import AppDispatcher from '../dispatcher.js';
import TodoConstant from '../constants/todoConstant.js';

class TodoAction {
  addItem(text) {
    AppDispatcher.dispatch({
      actionType: TodoConstant.ADD_ITEM,
      text
    });
  }
}

export default new TodoAction();

todoConstant.js是一个包含所有动作类型的常量对象:

// public/scripts/constants/todoConstant.js
export default {
  ADD_ITEM: 'TODO_ADD_ITEM'
};

数据分发中心

Dispatcher是一个分发中心,它管理着应用的所有数据流向。每一个Store在这里注册,同时提供一个回调函数:

// public/scripts/dispatcher.js
import { Dispatcher } from 'flux';

import TodoStore from './stores/todoStore';
import TodoConstant from './constants/todoConstant';

const AppDispatcher = new Dispatcher();

TodoStore.dispatchToken = AppDispatcher.register(payload => {
  switch (payload.actionType) {
    case TodoConstant.ADD_ITEM:
      TodoStore.addItem(payload.text);
      break;
    default:
  }
});

export default AppDispatcher;

上面代码中可以看到,当TodoAction告诉Dispatcher发生了一个动作时,TodoStore将会通过注册时的回调函数接受动作的行为。

数据层

TodoStore包含状态和业务逻辑。它的职责有点类似MVC中的model

// public/scripts/stores/todoStore.js
import EventEmitter from 'events';

class TodoStore extends EventEmitter {
  constructor() {
    super();
    this.items = [];
  }

  getAll() {
    return this.items;
  }

  addItem(text) {
    this.items.push(text);
    this.change();
  }

  change() {
    this.emit('change');
  }

  addListener(name, callback) {
    this.on(name, callback);
  }

  removeListener(name, callback) {
    this.removeListener(name, callback);
  }
}

export default new TodoStore();

当状态发生改变时,TodoStore将会通过事件形式通知Views

再看视图层

再回到TodoController中,我们初始化应用的状态,同时监听Store的状态改变事件:

// public/scripts/components/todoController.jsx
import React from 'react';

import TodoAction from '../actions/todoAction.js';
import TodoStore from '../stores/todoStore.js';
import Todo from './todo.jsx';

export default class TodoController extends React.Component {
  constructor(props) {
    super(props);
    this.state = { items: TodoStore.getAll() };
    this.onListChange = this.onListChange.bind(this);
  }

  componentDidMount() {
    TodoStore.addListener('change', this.onListChange);
  }

  componentWillUnmount() {
    TodoStore.removeListener('change', this.onListChange);
  }

  onListChange() {
    this.setState({
      items: TodoStore.getAll()
    });
  }

  newItem() {
    TodoAction.addItem('new item');
  }

  render() {
    return <Todo items={this.state.items} newItem={this.newItem} />;
  }
}

一旦TodoController接受到应用状态改变,将会触发Todo重新渲染。

References

LICENSE

MIT