javascript - 同一页面上单个商店的多次使用

标签 javascript reactjs mobx

我有一个商店,它执行 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"/>
    );
}

基于此代码,相同的图形存储被注入(inject)到两个组件中,导致 2 次提取出去,并且两个图形最终都具有相同的数据点 - 以最后出现的一个为准。

执行此操作的正确方法是什么?我只是以错误的方式思考这个问题吗?

最佳答案

有很多方法可以做到这一点,但我会利用 MobX 的面向对象特性,并创建一个数据存储,该数据存储被实例化并作为提供者传递给所有组件。如果愿意,您可以将其视为您的“本地数据库”。

然后只需在该数据存储上添加方法即可获取并创建不同的图表实例。

这是一些示例代码(无 typescript )

// 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 属性来启动获取

@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} />
    );
  }
}

关于javascript - 同一页面上单个商店的多次使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47009922/

相关文章:

javascript - 代码: Dealing with min and max - Javascript的解释

javascript - 将每 3 个字母转换为大写

reactjs - 使用 mergeProps 访问 mapDispatchToProps 中的状态

wordpress - React 应用程序渲染 html 实体,例如转义的 & 符号

javascript - 检测 'Enter' 的按键会阻止输入文本字段上的任何数据输入

javascript - 如何在 promise 的 componentDidMount 中设置状态而不会出现 setState 错误

javascript - 在时刻时间戳之前添加字符串

reactjs - 在 Reactjs 中动态生成导航栏?

reactjs - MobX 和 React Native 功能组件 : How can we implement mobX in React Native Functional Component?

reactjs - 如何同步到 react 中的存储实例?