从概念上讲,我如何编写通量存储以避免将不相关的数据混合在一起

Conceptually, how do I write my flux Stores to not mix up unrelated data together?

本文关键字:不相关 在一起 混合 数据 存储 概念上 何编写      更新时间:2023-09-26

假设我有一个依赖Flux的应用程序。

大多数Flux教程告诉您的Components应该监听Store上的change事件,并相应地渲染数据。这种方法非常适合小型和简单的用例,但是我在稍微复杂一点的场景中遇到了一个问题:

我有一份客户名单,我可以按居住城市(华盛顿、纽约等)进行筛选。此列表在url /customers/by-city下可用,可以用以下代码表示:

var CustomersList = React.createClass({
 
  getInitialState() {
    return {
      city: 'Washington',
      customers: []
    };
  },
 
  componentWillMount: function() {
    CustomersActions.retrieveForCity(this.state.city);
    CustomersStore.on('change', this.handleNewData);
  },
  componentWillUnmount: function() {
    CustomersStore.off('change', this.handleNewData);
  },
  render: function() {
    return <FilteredTable filters={['city']}
                          onCityChange={this.handleCityChange} 
                          data={this.state.customers} />;
  },
  handleCityChange: function(state) {
    CustomersActions.retrieveForCity(this.state.city);
    this.setState({city: city});
  },
  
  handleNewData: function(customers) {
    this.setState({customers: customers});
  }
});

每次我想按不同的城市进行筛选时,CustomersActions都会发出AJAX请求,响应会转到Dispatcher。然后CustomersStore拾取它,将其存储为data,并发出change事件。几乎是标准的Flux。

现在,据我所知,没有办法将change事件与它的实际行为联系起来。因此,想象以下场景:

  • 我用San Francisco过滤表格
  • 我改变了主意,在AJAX请求完成之前,我点击了一些导航链接(由react处理,没有页面重新加载),最后我会看到一个不同的url,例如/customers/shortlisted。此URL下还有另一个可用组件:ShortlistedCustomers
  • ShortlistedCustomers类似于CustomersList——为了显示数据,它通过CustomerActions发出ajax请求,并在CustomersStore上侦听change事件
  • 现在,技巧部分-第二个ajax请求在第一个请求之前完成,发出两个change事件,用户的表中出现错误的数据

如何"正确"解决此问题?我对最简单的解决方案感兴趣,也许是FB的人自己推荐的?我意识到我可以取消第一个AJAX,或者只按照发出请求的顺序处理响应,但这很快就会失控。

请注意,这个问题并不是针对这个案例的,但它是一个更普遍的问题。例如,如果我想添加更多的方式来触发AJAX请求,或者添加更多依赖于同一Store的组件,那么该解决方案应该适用。

当然,有几种可行的方法可以解决这种情况,每种方法都有自己的优缺点。以下是一些我认为仍然符合Flux的内容。

请记住,我不知道你的应用程序的全部范围,所以其中一些可能对你来说不可行。

客户商店收听已调度的API请求操作

  1. 发送一个操作以指示已发送API请求
  2. CustomersStore在调度此操作时清除其状态

也可以用于创建加载状态。

客户存储将其响应存储在存储桶中

  1. 为/by-city终结点请求的数据将存储在CustomersStore中的"byCity"哈希下
  2. "/by city的组件现在通过指定此哈希来访问其数据,例如CustomersStore.getData("byCity")"
  3. 以相同的方式存储和检索/入围的数据

现在您也许可以利用一些缓存逻辑。

创建重置客户的操作存储

  1. 当CustomersStore收到此"重置"操作时,它将清除其存储的数据
  2. /在适当的生命周期功能期间,按城市和/入围组件调度"重置"操作

这将帮助你在一个组件内处理同样的问题太

这些想法很少,我相信它们仍然会遵循Flux原理。希望这是有用的!

在更复杂的应用程序中,使用Reflux或Redux可能会做得更好。使用Reflux,您可以使用参数发射,让控制组件根据需要路由数据。

import Reflux from 'reflux';
import Actions from './Actions';
import AddonStore from './Addon.Store';
import MixinStoreObject from './Mixin.Store';
function _GotData(data) { this.data1 = data; BasicStore.trigger('data1'); }
let BasicStoreObject = {
	init() { this.listenTo(AddonStore, this.onAddonTrigger); },
	data1: {},
	listenables: Actions,
	mixins: [MixinStoreObject],
	onGotData1: _GotData,
	onAddonTrigger() { BasicStore.trigger('data2'); },
	getData1() { return this.data1; },
	getData2() { return AddonStore.data2; },
	getData3() { return this.data3; }
}
const BasicStore = Reflux.createStore(BasicStoreObject);
export default BasicStore;

import React from 'react';
import BasicStore from './../flux/Basic.Store';
let AppCtrlSty = {
	height: '100%',
	padding: '0 10px 0 0'
}
const getState = () => {
	return {
		Data1: BasicStore.getData1(),
		Data2: BasicStore.getData2(),
		Data3: BasicStore.getData3()
	};
};
class AppCtrlRender extends React.Component {
 	render() {
		let data1 = JSON.stringify(this.state.Data1, null, 2);
		let data2 = JSON.stringify(this.state.Data2, null, 2);
		let data3 = JSON.stringify(this.state.Data3, null, 2);
		return (
			<div id='AppCtrlSty' style={AppCtrlSty}>
				React 1.4 ReFlux with SuperAgent<br/><br/>
				Data1: {data1}<br/><br/>
				Data2: {data2}<br/><br/>
				Data3: {data3}<br/><br/>
			</div>
		);
	}
}
export default class AppCtrl extends AppCtrlRender {
	constructor() {
		super();
		this.state = getState();
	}
	componentDidMount() { this.unsubscribe = BasicStore.listen(this.storeDidChange.bind(this)); }
	componentWillUnmount() { this.unsubscribe(); }
	storeDidChange(id) {
		switch (id) {
			case 'data1': this.setState({Data1: BasicStore.getData1()}); break;
			case 'data2': this.setState({Data2: BasicStore.getData2()}); break;
			case 'data3': this.setState({Data3: BasicStore.getData3()}); break;
			default: this.setState(getState());
		}
	}
}

ShortListedCustomersCustomersList应具有/"从单独的存储中提取其数据"[或从公共存储中提取单独的属性]

当操作/存储触发数据已到达的事件时,只有当前渲染的组件才会使用适合它的数据重新渲染。

(话虽如此,我认为你应该转向redux,甚至是逐渐的-不可变性和reducer中的排序将帮助你解决这些问题)