什么是iflux ?
iflux = immutable.js + react.js
什么是React.js ?
React.js猶如Facebook的文化基因所強調的一樣move fast and break things, 在快速前進中打破了很多我們對于web開發的固有認識。
更厲害的是React把這種創新平移到移動開發(React native)實現了Learn once, Write everywhere.
React的特點。
強調組件化的開發方式(更高的抽象層次,更好的分離關注點)
聲明式的開發風格(更好的表現力)
單向的數據流動(簡單可預測)
超高性能的渲染60fps不是夢 (掌聲在哪里?)
最大的創新源于virtual dom (以及virtual native)
輕量,可以在現有的系統中快速試錯
精確的生命周期,更簡單的整合第三方的庫(jquery)
關于更多
因為React的定位就是輕量級高效組件式的view library,但是在我們實際的應用開發工程中不僅僅需要處理view的問題,更復雜的是對于狀態的控制。
官方的flux架構提供了一個很好的針對React的架構指導,但是代碼量很大。
說到底flux就是在解決一個數據流向以及控制狀態變化問題。這點om確實做的非常出色,
借助于Clojure的數據的特性(1. 數據不可變 2. 持久化數據結構 3.共享數據結構)在不斷的追尋下,immutable.js出現在了眼前,如獲至寶。
隨著對immutable.js深入挖掘,發現正好契合了React的架構特點,可以使用Immutable很好的管理我們的Store,因為Immutable強調值語義,
能夠更好的追蹤狀態的變化(cursor)且帶來了更好的性能。
整體思路
- 建議:優先選擇connectToStore
+-----------------------+
| WebApi |
+-----------------------+
|
\|/
+-----------------------+
| Store(immutable) |<-----+
+-----------------------+ |
| //es5的風格 |
| StoreMixin | msg(EventEmitter)
\|/ |
+------------------------+ |
| React App |-----|
+------------------------+
| <Layout> |
| <SearchForm/> |
| <Toolbar/> |
| <DataGrid/> |
| </Layout> |
+------------------------+
一個應用只有一個Store,單根數據源,單向數據流動,數據沉淀在頂層。
且通過PureRenderMix可以獲取更好的性能。簡直就是為React私人定制一般。
于是,順其自然的寫了iflux去更好的粘合React和immutable。
整體思路:
React只承擔view應該承擔的事情(1. 資料呈現 2. 用戶交互) 不處理任何的業務邏輯,就是根據數據去渲染dom即可,這樣view可以做的很輕。
應用的全部數據沉淀在一個Store中,當全部數據在頂層時,很多事情都變得簡單,因為獲取數據變得十分廉價。無論是校驗和對數據的轉換控制都變得非常簡單。
React只是取數據渲染,其他的比如狀態的變化全部通過事件pubsub通知appstore去更新數據。如果狀態不會影響其他組件的級聯變化可以放在組件內部消化掉。
所有的ajax封裝在webapi模塊中,全部promise化。回調回來通過cursor更新store, cursor更新store, store通知React去rerender。
區分View component 和 pure component。
如何使用?
mkdir hello
cd hello
npm init
npm install react immutable iflux --save
npm install babel-loader --save-dev
? iflux-demo tree -L 3
.
├── apps #we like django's app-style
│ └── index #app-name
│ ├── index.js #viewcontainer component
│ ├── component #collect of dump components
│ ├── store.js #immutable store
│ └── webapi.js #fetch remote resource
├── node_modules
├── package.json
└── webpack.config.js
5 directories, 4 files
例子
//webapi.js
export const fetchGithub = (name) => {
return fetch(`http://github.com/${name}`)
};
export default {
fetchGithub
};
//store.js
import { Store, msg } from 'iflux';
import { fromJS } from 'immutable';
import { fetchGithub } from './webapi';
const appStore = Store({
name: '',
githubInfo: {}
});
exports default appStore;
//when use immutable's cursor to update store
//react's view will auto re-render
msg.on('updateName', (name) => {
appStore.cursor().set('name', name);
});
msg.on('submit', async () => {
const data = await fetchGithub(name);
appStore.cursor.set('githubInfo', fromJS(data));
});
//index.js
//es5的樣式
import React from 'react';
import {msg, mixins} from 'iflux';
import appStore from './store';
const {StoreMixin} = mixins;
const IfluxApp = React.createClass({
//自動將Store中的data混入到state
mixins: [StoreMixin(appStore)],
render() {
var store = appStore.data();
return (
<div>
<form onSubmit={this._submit}>
<input name="name" onChange={this._handleChange}/>
</form>
<div>
{store.get('githubInfo')}
</div>
</div>
);
},
_handleChange(e) {
msg.emit('updateName', e.target.value);
},
_submit() {
msg.emit('getGithubInfo');
}
});
//es6的樣式
import React from 'react';
import { msg, connectToStore } from 'iflux';
import appStore from './store';
class IfluxApp extends React.Component {
render() {
const {store} = this.props;
return (
<div>
<form onSubmit={this._submit}>
<input name="name" onChange={this._handleChange}/>
</form>
<div>
{store.get('githubInfo')}
</div>
</div>
);
}
}
export default connectToStore(appStore)(IfluxApp);