使用mobx创建多个商店并将其注入到组件的正确方法-ReactJs

时间:2019-01-27 22:31:21

标签: reactjs mobx mobx-react state-management

如Mobx documentation中的建议,我以以下方式创建了多个商店:

class bankAccountStore {
  constructor(rootStore){
    this.rootStore = rootStore;
  }
...

class authStore {
  constructor(rootStore){
    this.rootStore = rootStore;
  }
...

最后通过以下方式创建根存储。同样I prefer可以在master's store构造函数中构造子存储。而且,我发现有时候我的子存储必须观察父存储中的一些数据,所以我将其传递给子构造器

class RootStore {
  constructor() {
    this.bankAccountStore = new bankAccountStore(this);
    this.authStore = new authStore(this);
  }
}

通过以下方式提供给应用

<Provider rootStore={new RootStore()}>
  <App />
</Provider>

然后以这种方式注入组件

@inject('rootStore') 
@observer
class User extends React.Component{
  constructor(props) {
    super(props);
    //Accessing the individual store with the help of root store
    this.authStore = this.props.rootStore.authStore;
  }
}

即使需要根存储的一部分,它也是每次都将根存储注入到组件的正确有效的方法吗?如果不是,如何将Auth Store注入用户组件?

编辑:我已经完成了github讨论的答案。答案中提供的讨论链接

3 个答案:

答案 0 :(得分:3)

我建议您拥有多个商店,以避免连锁商店。正如我们在应用程序中所做的:

class RootStore {
    @observable somePropUsedInOtherStores = 'hello';
}

class AuthStore {
    @observeble user = 'Viktor' ; 

    constructor(rootStore) {
        this.rootStore = rootStore;
    }

    // this will reevaluate based on this.rootStore.somePropUsedInOtherStores cahnge
    @computed get greeting() {
        return `${this.rootStore.somePropUsedInOtherStores} ${this.user}`
    }
}

const rootStore = new RootStore();

const stores = {
    rootStore,
    bankAccountStore: new BankAccountStore(rootStore),
    authStore = new AuthStore(rootStore) 
}

<Provider {...stores}>
  <App />
</Provider>

通过这种方式,您可以精确地访问所需的商店,因为大多数商店都覆盖一个域实例。尽管如此,两个子商店都可以与rootStore通信。在其上设置属性或调用方法。

如果您不需要跨商店通信-您可能根本不需要rootStore。删除它,不要传递给其他商店。只需保留两个兄弟姐妹商店

回答关于不注资整个商店的问题,您可能会受益于mapperFunction(例如redux中的mapStateToPropsdocs here

@inject(stores => ({
        someProp: stores.rootStore.someProp
    })
)
@observer
class User extends React.Component {
// no props.rootStore here, only props.someProp

}

答案 1 :(得分:1)

这个答案可能是有根据的,但它可能间接地对社区有所帮助。
经过大量研究,我看到了许多人在实践中使用的以下方法。常规方法有一个根存储,可以用作存储之间的通信通道。

问题1:如何组织商店并将其注入到组件中?

方法1:

  

App.js

// Root Store Declaration
class RootStore {
    constructor() {
      this.userStore = new UserStore(this);
      this.authStore = new AuthStore(this);
    }
}    
const rootStore = new RootStore()

// Provide the store to the children
<Provider 
    rootStore={rootStore}
    userStore={rootStore.userStore}
    authStore={rootStore.authStore}
>
  <App />
</Provider>
  

Component.js

// Injecting into the component and using it as shown below
@inject('authStore', 'userStore')
@observer
class User extends React.Component {
    // only this.props.userStore.userVariable
}

方法2:

  

App.js

class RootStore {
    constructor() {
      this.userStore = new UserStore(this);
      this.authStore = new AuthStore(this);
    }
} 
const rootStore = new RootStore()

<Provider rootStore={rootStore}>
  <App />
</Provider>
  

Component.js

// Injecting into the component and using it as shown below
@inject(stores => ({
    userStore: stores.userStore,
    authStore: stores.authStore,
    })
)
@observer
class User extends React.Component {
    // no this.props.rootStore.userStore,userVariable here, 
    // only this.props.userStore.userVariable
}

方法1和方法2除了语法差异外没有其他差异。好的!那是注射部分!

问题2:如何进行店间交流? (尝试避免)

  

现在我知道一个好的设计可以使商店保持独立并且   耦合较少。但以某种方式考虑一种情况,我想要   UserStore中的变量会更改AuthStore中的某个变量   被改变了。使用Computed。上述两种方法都通用这种方法

     

AuthStore.js

export class AuthStore {    
    constructor(rootStore) {
        this.rootStore = rootStore
        @computed get dependentVariable() {
          return this.rootStore.userStore.changeableUserVariable;                                      
        }
    }
}
  

我希望这对社区有所帮助。有关更详细的讨论,您可以   请参阅issue raised by me on Github

答案 2 :(得分:0)

在将其传递给提供程序之前直接在api.js文件中初始化RootStore有时不是您想要的。 这可以使将主商店类的实例注入到其他js文件中变得更加困难:

示例1:

app.js-在将新实例传递给提供者之前创建它:

//Root Store Declaration
class RootStore {
    constructor() {
      ...
    }
}    

const rootStore = new RootStore()

// Provide the store to the children
<Provider rootStore={rootStore}>
  <App />
</Provider>

示例2:

RootStore.js-直接在RootStore类中创建新实例:

// Root Store Declaration
class RootStore {
    constructor() {
      ...
    }
}    

export default new RootStore();
Example 1相比,

Example 2使得访问/注入应用程序另一部分中的商店变得更加困难,如下面所述的Api.js

Api.js文件代表axios包装器(在我的情况下,它处理全局加载指示符):

import rootStore from '../stores/RootStore'; //right RootStore is simply imported

const axios = require('axios');
const instance = axios.create({
 ...
});

// Loading indicator
instance.interceptors.request.use(
    (request) => {
        rootStore.loadingRequests++;
        return request;
    },
    (error) => {
        rootStore.loadingRequests--; 
        return Promise.reject(error);
    }
)

使用React Hooks,您可以通过这种方式注入商店:

import { observer, inject } from "mobx-react";
const YourComponent = ({yourStore}) => {
      return (
          ...
      )
}

export default inject('yourStore')(observer(YourComponent));