在同一页面上多次使用单个商店
Multiple uses of single store on same page
我有一家商店执行 fetch
以使用来自 mobx-utils 的 asyncAction
从我的服务器获取图形数据。
看起来像这样:
class GraphStore {
@observable
public loading: boolean;
@observable
public datapoints: any[];
@asyncAction
*fetch(id: string) {
const datapoints = yield fetch('/api/datapoints');
this.loading = false;
this.datapoints = datapoints;
}
}
在我的组件中,我是这样使用它的:
@inject(STORE_GRAPH)
class Graph {
componentWillMount() {
const graphStore= this.props[STORE_GRAPH] as GraphStore;
const { id } = this.props;
graphStore.fetch(id);
}
render(){
const graphStore= this.props[STORE_GRAPH] as GraphStore;
if(graphStore.loading)
return <h2>Loading</h2>
return (
<Chart datapoints={graphStore.datapoints}/>
);
}
这很好用,但是当我想扩展它以在同一页上显示 2 个图表时,我不知道该怎么做?基本上我想要一个像这样的父组件:
render() {
return (
<Graph id="foo"/>
<Graph id="bar"/>
);
}
根据这段代码,相同的图形存储被注入到两个组件中,导致 2 次提取失败,并且两个图形最终都具有相同的数据点 - 以最后出现的数据点为准。
执行此操作的正确方法是什么?我是不是想错了?
有很多方法可以做到这一点,但我会利用 MobX 面向对象的特性,并创建一个数据存储,将其实例化并作为提供者传递给所有组件。如果愿意,您可以将其视为您的 "local db"。
然后只需在该数据存储上添加方法来获取和创建图形的不同实例。
这是一些示例代码(没有打字稿)
// stores/data.js
import Graph from './Graph';
class DataStore {
@observable graphs = observable.map();
@action getGraphById(id) {
if (!this.graphs.has(id)) {
this.graphs.set(id, new Graph(id))
}
return this.graphs.get(id);
}
}
export default new DataStore();
然后创建一个可实例化的Graph对象
// stores/Graph.js
export default class Graph {
@observable id;
@observable loading = false;
@observable datapoints = [];
constructor(id) {
this.id = id;
if (!this.hasData) {
this.fetch();
}
}
@computed get hasData() {
return this.datapoints.length;
}
@action async fetch() {
this.loading = true;
const datapoints = await fetch(`/api/datapoints/${this.id}`);
this.loading = false;
this.datapoints = datapoints;
}
}
在您的组件树中,您将通过提供程序向下传递数据存储
import dataStore from './stores/data'
<Provider stores={{ data: dataStore }}>
<Graph id="foo" />
<Graph id="bar" />
</Provider>
然后只需在组件中使用 id prop 来启动 fetch
@inject('data')
@observer
class Graph extends Component {
@observable graph;
componentWillMount() {
const { id, data } = this.props;
this.graph = data.getGraphById(id);
}
render() {
if (this.graph.loading) {
return <h2>Loading</h2>
}
return (
<Chart datapoints={this.graph.datapoints} />
);
}
}
我有一家商店执行 fetch
以使用来自 mobx-utils 的 asyncAction
从我的服务器获取图形数据。
看起来像这样:
class GraphStore {
@observable
public loading: boolean;
@observable
public datapoints: any[];
@asyncAction
*fetch(id: string) {
const datapoints = yield fetch('/api/datapoints');
this.loading = false;
this.datapoints = datapoints;
}
}
在我的组件中,我是这样使用它的:
@inject(STORE_GRAPH)
class Graph {
componentWillMount() {
const graphStore= this.props[STORE_GRAPH] as GraphStore;
const { id } = this.props;
graphStore.fetch(id);
}
render(){
const graphStore= this.props[STORE_GRAPH] as GraphStore;
if(graphStore.loading)
return <h2>Loading</h2>
return (
<Chart datapoints={graphStore.datapoints}/>
);
}
这很好用,但是当我想扩展它以在同一页上显示 2 个图表时,我不知道该怎么做?基本上我想要一个像这样的父组件:
render() {
return (
<Graph id="foo"/>
<Graph id="bar"/>
);
}
根据这段代码,相同的图形存储被注入到两个组件中,导致 2 次提取失败,并且两个图形最终都具有相同的数据点 - 以最后出现的数据点为准。
执行此操作的正确方法是什么?我是不是想错了?
有很多方法可以做到这一点,但我会利用 MobX 面向对象的特性,并创建一个数据存储,将其实例化并作为提供者传递给所有组件。如果愿意,您可以将其视为您的 "local db"。
然后只需在该数据存储上添加方法来获取和创建图形的不同实例。
这是一些示例代码(没有打字稿)
// stores/data.js
import Graph from './Graph';
class DataStore {
@observable graphs = observable.map();
@action getGraphById(id) {
if (!this.graphs.has(id)) {
this.graphs.set(id, new Graph(id))
}
return this.graphs.get(id);
}
}
export default new DataStore();
然后创建一个可实例化的Graph对象
// stores/Graph.js
export default class Graph {
@observable id;
@observable loading = false;
@observable datapoints = [];
constructor(id) {
this.id = id;
if (!this.hasData) {
this.fetch();
}
}
@computed get hasData() {
return this.datapoints.length;
}
@action async fetch() {
this.loading = true;
const datapoints = await fetch(`/api/datapoints/${this.id}`);
this.loading = false;
this.datapoints = datapoints;
}
}
在您的组件树中,您将通过提供程序向下传递数据存储
import dataStore from './stores/data'
<Provider stores={{ data: dataStore }}>
<Graph id="foo" />
<Graph id="bar" />
</Provider>
然后只需在组件中使用 id prop 来启动 fetch
@inject('data')
@observer
class Graph extends Component {
@observable graph;
componentWillMount() {
const { id, data } = this.props;
this.graph = data.getGraphById(id);
}
render() {
if (this.graph.loading) {
return <h2>Loading</h2>
}
return (
<Chart datapoints={this.graph.datapoints} />
);
}
}