前言
眾所周知惦银,React跟Flux是一對(duì)好基友咆课。
其中,市場(chǎng)流行的Flux有Redux扯俱,Mobx书蚪,Reflux。
其中迅栅,用法最簡單的是Reflux殊校。
其數(shù)據(jù)流思路如下:
+---------+ +--------+ +-----------------+
| Actions |------>| Stores |------>| View Components |
+---------+ +--------+ +-----------------+
^ |
+--------------------------------------+
我們能否再減少其數(shù)據(jù)流路徑?如下:
+--------+ +-----------------+
| Stores |------>| View Components |
+--------+ +-----------------+
^ |
----------------------+
兩個(gè)字读存,可以为流。
需求分析
- 集成Actions的功能到Stores。從而拿掉單獨(dú)的Actions让簿。
- 集成組件的State和Store在一起敬察。
- 跨組件通信依賴其Store。
擼函數(shù)
這意味著我們的createStore
是一個(gè)工廠函數(shù)尔当。
用來生產(chǎn)每一個(gè)React組件實(shí)例對(duì)應(yīng)的Store實(shí)例莲祸。
function isObject(obj) {
return Object.prototype.toString.call(obj) == '[object Object]';
}
function extend(obj) {
if (!isObject(obj)) {
return obj;
}
for (let i = 1, length = arguments.length; i < length; i++) {
let source = arguments[i];
for (let prop in source) {
if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
let propertyDescriptor = Object.getOwnPropertyDescriptor(source, prop);
Object.defineProperty(obj, prop, propertyDescriptor);
} else {
obj[prop] = source[prop];
}
}
}
return obj;
}
function createStore(definition={}) {
function Store() {
let t = this;
t.data = null;
extend(t, definition);
t.trigger = function () {
this.setState({});
}
}
let store = new Store();
return store;
};
isObject
和extend
這兩個(gè)函數(shù)按下不表。
其中,extend
函數(shù)是用來對(duì)象合并锐帜,該函數(shù)某部位依賴isObject
田盈。((__) 嘻嘻……)
createStore
函數(shù)產(chǎn)出的實(shí)例內(nèi)部
-
data
作為組件實(shí)例的store。 -
trigger
作為更新組件實(shí)例的方法缴阎。
萬事具備允瞧,只欠東風(fēng)。
接下來就是用connect
函數(shù)把組件實(shí)例和Store實(shí)例連接在一起药蜻。
function connect(listenable, context) {
if(!isObject(listenable)){
throw new Error('connect function\'s argument is not a object');
}
return {
componentDidMount() {
context = context || this;
listenable.trigger = listenable.trigger.bind(context);
},
componentWillUnmount() {
listenable.trigger = null;
}
};
}
借用React組件生命周期瓷式,在其componentDidMount
階段替饿,
改變Store實(shí)例的trigger
上下文语泽,使其指向React組件實(shí)例,
從而方便trigger
調(diào)用React組件實(shí)例的setState
方法视卢。
全套代碼如下:
擼Demo
- Samflux.js
function isObject(obj) {
return Object.prototype.toString.call(obj) == '[object Object]';
}
function extend(obj) {
if (!isObject(obj)) {
return obj;
}
for (let i = 1, length = arguments.length; i < length; i++) {
let source = arguments[i];
for (let prop in source) {
if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
let propertyDescriptor = Object.getOwnPropertyDescriptor(source, prop);
Object.defineProperty(obj, prop, propertyDescriptor);
} else {
obj[prop] = source[prop];
}
}
}
return obj;
}
exports.createStore = function (definition={}) {
function Store() {
let t = this;
t.data = null;
extend(t, definition);
t.trigger = function () {
this.setState({});
}
}
let store = new Store();
return store;
};
exports.connect = function (listenable, context) {
if(!isObject(listenable)){
throw new Error('connect function\'s argument is not a object');
}
return {
componentDidMount() {
context = context || this;
listenable.trigger = listenable.trigger.bind(context);
},
componentWillUnmount() {
listenable.trigger = null;
}
};
}
- store.js
const Samflux = require('./Samflux.js');
const Store = Samflux.createStore({
data:'old data',
onSetData: function(){
this.data = 'new data';
this.trigger();
},
});
module.exports = Store;
- SamfluxTest.js
const Store = require('./store.js');
const Samflux = require('./Samflux.js');
const reactMixin = require('react-mixin');
const React = window.React;
require('./SamfluxTest.less');
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
setData(){
Store.onSetData();
}
render() {
const me = this;
return (<div className="SamfluxTest" onClick={me.setData.bind(this)}><span>{Store.data}</span></div>);
}
}
reactMixin.onClass(Test, Samflux.connect(Store));
module.exports = Test;