Flux
Flux
Dispatcher
大部分情况下我们在系统中只需要单个的
const Dispatcher = function() {
return {
_stores: [],
register: function(store) {
this._stores.push({ store: store });
},
dispatch: function(action) {
if (this._stores.length > 0) {
this._stores.forEach(function(entry) {
entry.store.update(action);
});
}
}
};
};
在上述实现中我们会发现,每个传入的Store
对象都应该拥有一个update
方法,因此我们在进行
register: function (store) {
if (!store || !store.update) {
throw new Error('You should provide a store that has an `update` method.');
} else {
this._stores.push({ store: store });
}
}
在完成了对于
很多
Framework.attachToStore(view, store);
不过作者并不是很喜欢这种方式,这样这样会要求React mixins
const View = React.createClass({
mixins: [Framework.attachToStore(store)]
...
});
使用 mixin
是个不错的修改现有的React context
,这种方式允许我们将值跨层次地传递给
function attachToStore(Component, store, consumer) {
const Wrapper = React.createClass({
getInitialState() {
return consumer(this.props, store);
},
componentDidMount() {
store.onChangeEvent(this._handleStoreChange);
},
componentWillUnmount() {
store.offChangeEvent(this._handleStoreChange);
},
_handleStoreChange() {
if (this.isMounted()) {
this.setState(consumer(this.props, store));
}
},
render() {
return <Component {...this.props} {...this.state} />;
}
});
return Wrapper;
}
其中Component
代指我们需要附着到Store
中的consumer
则是应该被传递给
class MyView extends React.Component {
// ...
}
ProfilePage = connectToStores(MyView, store, (props, store) => ({
data: store.get("key")
}));
这种模式的优势在于其有效地分割了各个模块间的职责,在该模式中
register: function (store) {
if (!store || !store.update) {
throw new Error('You should provide a store that has an `update` method.');
} else {
const consumers = [];
const change = function () {
consumers.forEach(function (l) {
l(store);
});
};
const subscribe = function (consumer) {
consumers.push(consumer);
};
this._stores.push({ store: store, change: change });
return subscribe;
}
return false;
},
dispatch: function (action) {
if (this._stores.length > 0) {
this._stores.forEach(function (entry) {
entry.store.update(action, entry.change);
});
}
}
另一个常见的用户场景就是我们需要为界面提供一些默认的状态,换言之当每个consumer
注册的时候需要提供一些初始化的默认数据
consumers.push(consumer);
!noInit ? consumer(store) : null;
};
综上所述,最终的
const Dispatcher = function() {
return {
_stores: [],
register: function(store) {
if (!store || !store.update) {
throw new Error(
"You should provide a store that has an `update` method."
);
} else {
const consumers = [];
const change = function() {
consumers.forEach(function(l) {
l(store);
});
};
const subscribe = function(consumer, noInit) {
consumers.push(consumer);
!noInit ? consumer(store) : null;
};
this._stores.push({ store: store, change: change });
return subscribe;
}
return false;
},
dispatch: function(action) {
if (this._stores.length > 0) {
this._stores.forEach(function(entry) {
entry.store.update(action, entry.change);
});
}
}
};
};
Actions
{
"type": "USER_LOGIN_REQUEST",
"payload": {
"username": "...",
"password": "..."
}
}
其中的type
属性表明该payload
中包含了相关的数据。另外,在某些情况下
const createAction = function(type) {
if (!type) {
throw new Error("Please, provide action's type.");
} else {
return function(payload) {
return dispatcher.dispatch({ type: type, payload: payload });
};
}
};
Final Code
上文我们已经了解了核心的
const createSubscriber = function(store) {
return dispatcher.register(store);
};
并且为了不直接暴露createAction
与createSubscriber
这两个函数
const Dispatcher = function() {
return {
_stores: [],
register: function(store) {
if (!store || !store.update) {
throw new Error(
"You should provide a store that has an `update` method."
);
} else {
const consumers = [];
const change = function() {
consumers.forEach(function(l) {
l(store);
});
};
const subscribe = function(consumer, noInit) {
consumers.push(consumer);
!noInit ? consumer(store) : null;
};
this._stores.push({ store: store, change: change });
return subscribe;
}
return false;
},
dispatch: function(action) {
if (this._stores.length > 0) {
this._stores.forEach(function(entry) {
entry.store.update(action, entry.change);
});
}
}
};
};
module.exports = {
create: function() {
const dispatcher = Dispatcher();
return {
createAction: function(type) {
if (!type) {
throw new Error("Please, provide action's type.");
} else {
return function(payload) {
return dispatcher.dispatch({ type: type, payload: payload });
};
}
},
createSubscriber: function(store) {
return dispatcher.register(store);
}
};
}
};