如何与Flux中的外部服务进行通信,plenty discussion。{/ p>
很明显,基本工作流程是触发HTTP请求,最终会根据响应调度成功或失败操作。您也可以选择发送"进行中"在提出请求之前采取行动。
但是,如果请求的参数取决于商店的状态呢?似乎没有人提到它。
基本上,根据用户与视图的交互,调度ACTION。 Store拥有关于如何在给定ACTION的情况下从当前state0转换到下一个state1的逻辑。需要来自state1的数据才能正确形成新的HTTP请求。
例如,用户在页面上选择一个新过滤器,而商店决定也重置分页。这应该会导致新的HTTP请求(新的过滤器值,第一页),而不是(新的过滤器值,来自state0的当前页面)。
View无法通过用户的交互使HTTP调用本身正确,因为它必须复制商店的逻辑才能转换到下一个状态。
View无法在其商店的onChange处理程序中进行HTTP调用,因为此时不再知道状态更改的来源是什么。
在转换到下一个状态后,在动作处理程序中使存储触发HTTP请求看起来是一个可行的选项。但是这会使这个动作隐式启动HTTP调用,这会禁止为调试提供可重放的调度操作日志。
在Flux中应该在哪里发起HTTP请求?
答案 0 :(得分:1)
让我们从底部开始:
在转换到下一个状态后,在动作处理程序中使存储触发HTTP请求看起来是一个可行的选项。但是这会使这个动作隐式启动HTTP调用,这会禁止为调试提供可重放的调度操作日志。
如果您处于调试/重播模式,则可以通过不启动HTTP请求来缓解此问题。只要您在HTTP请求处理程序中执行唯一操作是火灾操作(例如SUCCESS
和FAILURE
操作),这就非常有用。您可以使用简单的全局布尔值(if (!debug) { httpReq(...) }
)来实现它,但您也可以使模式更正式。
在Event Sourcing用语中,您将Gateways用于此目的。在正常操作中,网关发出您的HTTP请求,在调试中,您关闭网关(因此它不会发出任何HTTP请求)。
那就是说,我认为问题实际上可以通过重新考虑你的HTTP请求的位置来解决。
基本上,根据用户与视图的交互,调度ACTION。 Store拥有关于如何在给定ACTION的情况下从当前state0转换到下一个state1的逻辑。需要来自state1的数据才能正确形成新的HTTP请求。
在您问题的第二个链接(Where should ajax request be made in Flux app?)中,I recommend在行动创作者中进行写作,但在商店中读取。如果您将该模式推断到您的用例中,您可能会得到类似这样的内容(为了清晰起见,伪代码和长变量名称):
class DataTable extends React.Component {
render() {
// Assuming that the store for the data table contains two sets of data:
// one for the filter selection and one for the pagination.
// I'll assume they're passed as props here; this also assumes that
// this component is somehow re-rendered when the store changes.
var filter = this.props.filter;
var start = this.props.start;
var end = this.props.end;
var data = this.props.dataTableStore.getDataForPageAndFilter(
start, end, filter
);
// the store will either give us the LOADING_TOKEN,
// which indicates that the data is still loading,
// or it will give us the loaded data
if (data === DataTableStore.LOADING_TOKEN) {
return this.renderLoading();
} else {
return this.renderData(data);
}
}
}
class DataTableStore {
constructor() {
this.cache = {};
this.filter = null;
this.start = 0;
this.end = 10;
}
getDataForPageAndFilter(start, end, filter) {
var url = HttpApiGateway.urlForPageAndFilter(start, end, filter);
// in a better implementation, the HttpApiGateway
// might do the caching automatically, rather than
// making the store keep the cache
if (!this.cache[url]) {
this.cache[url] = DataTableStore.LOADING_TOKEN;
HttpApiGateway.query(url)
.then((response) => {
// success
var payload = {
url: url,
data: response.body
};
dispatch(DATA_FETCH_SUCCESS, payload);
}, (error) => {
// error
dispatch(DATA_FETCH_FAIL, { ... });
});
}
return this.cache[url];
}
handleChangeFilterAction(action) {
this.filter = action.payload.filter;
// the store also decides to reset pagination
this.start = 0;
this.end = 10;
this.emit("change");
}
handleDataFetchSuccessAction(action) {
this.cache[action.payload.url] = data;
this.emit("change");
}
handleDataFetchFailAction(action) {
// ...
}
}
DataTableStore.LOADING_TOKEN = "LOADING"; // some unique value; Symbols work well
您可以看到商店负责决定如何更新分页和过滤器变量,但不负责决定何时应该发出HTTP请求。相反,视图只是请求一些数据,如果商店没有在缓存中,它将然后发出HTTP请求。
这也允许视图将任何其他本地状态传递到getter中(如果HTTP请求也依赖于本地状态)。
答案 1 :(得分:0)
我不确定理解问题的所有部分,但会尝试回答一些有用的见解。
Flux有点像前端开发人员尚未成熟的EventSourcing / CQRS / Domain-Driven-Design版本
我们在后端使用类似于Flux的东西,使用不同的术语。我们可以将 Flux ActionCreators与DDD命令和 Flux操作与DDD事件进行比较。
命令表示用户意图(LOAD_TIMELINE(过滤器))。最终会发布一些事件的命令处理程序可以接受或拒绝它。在UI中,拒绝命令并没有多大意义,因为您不希望显示用户不应该单击的按钮...
事件代表发生的事情(总是在过去)。
驱动UI的React应用程序状态然后以某种方式将事件日志投影到json状态。如果没有首先触发事件,UI上不会显示任何内容。
回答您的问题
但是,如果请求的参数依赖于商店的状态呢?似乎没有人 提到它。
在DDD中,命令处理程序实际上可以是有状态的。他们可以使用app状态来了解如何正确处理命令。不知何故,这意味着您的Flux ActionBuilders也可以是有状态的(也许他们可以使用一些商店数据)
基本上,基于用户与视图的交互,ACTION就是 出动。 Store拥有如何从当前状态0转换的逻辑 给予ACTION下一个state1。需要来自state1的数据 正确形成新的HTTP请求。
在DDD中有一个名为 Saga (或进程管理器)的概念。 为简单起见,它接收事件流并可以生成新命令。
所以基本上你可以通过Saga表达你的要求:当有一个事件“FILTERS_UPDATED”时,用新的过滤器发出命令“RELOAD_LIST”。我很确定你可以用任何Flux实现类似的东西。
当您重播事件日志时,应该禁用Sagas,因为重放事件日志不应具有触发新事件等副作用。
我的Atom-React框架支持这些语义,其中商店可以充当有状态的命令处理程序或传奇。