chili 默默学编程

React 技术栈(四):框架(Flux 入门)


原文在此:

http://www.ruanyifeng.com/blog/2016/01/flux.html#comment-text


1、为什么要用框架

React 本身只涉及UI层,如果搭建大型应用,必须搭配一个前端框架。

也就是说,你至少要学两样东西,才能基本满足需要:React + 前端框架。

Facebook官方使用的是 Flux 框架。

本文就介绍如何在 React 的基础上,使用 Flux 组织代码和安排内部逻辑,使得你的应用更易于开发和维护。


2、安装

$ git clone https://github.com/ruanyf/extremely-simple-flux-demo.git
$ cd extremely-simple-flux-demo && npm install
$ npm start

安装后,访问 localhost:8080

示例的样式如下:


点击 New Item 按钮,生成上面的内容


3、文档结构


文件结构如下:

- 两个入口文件:index.html,index.jsx

- components 文件夹:包括 MyButton.jsx 和 MyButtonController.jsx

- actions 文件夹:包括 ButtonActions.js

- dispatcher 文件夹:包括 AppDispatcher.js

- stores 文件夹:包括 ListStroe.js


4、view 部分

view 由 index.html、 index.jsx、 components 文件夹里两个文件 MyButton.jsx、 MyButtonController.jsx组成。


index.html 提供一个真实的 dom 元素:

<html>
<body>
<div id="example"></div>
<script src="init.js"></script>
<script src="bundle.js"></script>
</body>
</html>


index.jsx 生成一个虚拟的 dom 元素,插入 index.html 中:

var React = require('react');
var ReactDOM = require('react-dom');
var MyButtonController = require('./components/MyButtonController');

ReactDOM.render(
<MyButtonController/>,
document.querySelector('#example')
);


虚拟的 dom 元素来自 components - MyButtonController.jsx:

var React = require('react');
var ListStore = require('../stores/ListStore');
var ButtonActions = require('../actions/ButtonActions');
var MyButton = require('./MyButton');

var MyButtonController = React.createClass({
getInitialState: function () {
return {
items: ListStore.getAll()
};
},

componentDidMount: function() {
ListStore.addChangeListener(this._onChange);
},

componentWillUnmount: function() {
ListStore.removeChangeListener(this._onChange);
},

_onChange: function () {
this.setState({
items: ListStore.getAll()
});
},

createNewItem: function (event) {
ButtonActions.addNewItem('new item');
},

render: function() {
return <MyButton
items={this.state.items}
onClick={this.createNewItem}
/>;
}

});

module.exports = MyButtonController;

对于上述代码的详细解释

- 模块输出的是一个 MyButtonController

MyButtonController 是一个 React 对象(React.createClass)

- 这个对象的输出,是一个 MyButton 组件 

    - MyButton 组件的参数是 items = MyButtonController.state.items

    - MyButton 组件的方法是 onClick = MyButtonController.creatNewItem

- 这个对象的方法包括:

    - 初始化状态(getInitialState),从 ListStore 中通过 getAll 方法活动所有 items

    - 组件加载后,关联到 ListStore change 事件,ListStore change 时,组件自动获取所有 items,通过 ListStore 的 getAll 方法

    - 组件卸载前,删除上述关联方法

    - createNewItem,此方法触发时,关联到 ButtonActions.addNewItem 事件


MyButtonController.jsx 渲染出来的是一个 MyButton 组件,来自 components - MyButton.jsx:

var React = require('react');

var MyButton = function(props) {
var items = props.items;
var itemHtml = items.map(function (listItem, i) {
return <li key={i}>{listItem}</li>;
});

return <div>
<ul>{itemHtml}</ul>
<button onClick={props.onClick}>New Item</button>
</div>;
};

module.exports = MyButton;

MyButton 是一个纯组件


5、action 部分

MyButton onClick 事件 

    - 触发 MyButtonController 里的 createNewItem 事件

    - 触发 ButtonActions 里的 addNewItem 事件

ButtonActions 代码:

var AppDispatcher = require('../dispatcher/AppDispatcher');

var ButtonActions = {

addNewItem: function (text) {
AppDispatcher.dispatch({
actionType: 'ADD_NEW_ITEM',
text: text
});
},

};

module.exports = ButtonActions;


6、dispatcher 部分

ButtonActions 里的 addNewItem 事件

    - 触发 AppDispatch.js 中的 'ADD_NEW_ITEM' action

AppDispatch.js 代码:

var Dispatcher = require('flux').Dispatcher;
var AppDispatcher = new Dispatcher();
var ListStore = require('../stores/ListStore');

AppDispatcher.register(function (action) {
switch(action.actionType) {
case 'ADD_NEW_ITEM':
ListStore.addNewItemHandler(action.text);
ListStore.emitChange();
break;
default:
// no op
}
})

module.exports = AppDispatcher;


7、store 部分

AppDispatch.js 中的 'ADD_NEW_ITEM' action 有两个动作:

    - 执行 ListStore 中的 addNewItemHandler ,参数为 MyButtonController 中传过来的 ‘new item‘

    - 执行 ListStroe 中的 emitChange

ListStore:

var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');

var ListStore = assign({}, EventEmitter.prototype, {
items: [],

getAll: function () {
return this.items;
},

addNewItemHandler: function (text) {
this.items.push(text);
},

emitChange: function () {
this.emit('change');
},

addChangeListener: function(callback) {
this.on('change', callback);
},

removeChangeListener: function(callback) {
this.removeListener('change', callback);
}
});

module.exports = ListStore;


8、完整的过程:

- 简易示意图:



- 详细示意图:



- 过程文字描述:

    - 初始化生成元素:

        - 生成一个 MyButtonController 替换 真实 dom 里的 div

        - MyButtonController 渲染出来的是一个 MyButton

        - MyButton 的参数是 MyButtonController 的 items

        - MyButton 有一个 onClick 方法,触发时,调用 MyButtonController 的 createNewItem 方法

    - 初始化获得数据:

        - MyButtonController 获取 ListStore 所有的 items,并渲染给 MyButton

    - 发生点击事件时(依次传递):

        - MyButton onClick 事件

        - MyButtonController createNewItem 事件

        ButtonActions addNewItem 事件

        - AppDispatcher ADD_NEW_ITEM

        - ListStore addNewItemHandler + EmitChange

        - MyButtonController setState items,重新渲染 MyButton 组件




reply ( 0 )