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

une*_*et7 5 state-management reactjs mobx mobx-react

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

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

class authStore {
  constructor(rootStore){
    this.rootStore = rootStore;
  }
...
Run Code Online (Sandbox Code Playgroud)

最后以以下方式创建根存储。另外,我更喜欢在master商店构造函数中构造子商店。此外,我发现有时我的子存储必须观察父存储的一些数据,因此我将其传递给子构造函数

class RootStore {
  constructor() {
    this.bankAccountStore = new bankAccountStore(this);
    this.authStore = new authStore(this);
  }
}
Run Code Online (Sandbox Code Playgroud)

通过以下方式提供给应用

<Provider rootStore={new RootStore()}>
  <App />
</Provider>
Run Code Online (Sandbox Code Playgroud)

然后像这样注入组件

@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;
  }
}
Run Code Online (Sandbox Code Playgroud)

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

编辑:我已经做出了结束github讨论的答案。答案中提供的讨论链接

une*_*et7 16

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

问题一:如何组织stores并注入到组件中?

方法一:

应用程序.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>
Run Code Online (Sandbox Code Playgroud)

组件.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
}
Run Code Online (Sandbox Code Playgroud)

方法二:

应用程序.js

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

<Provider rootStore={rootStore}>
  <App />
</Provider>
Run Code Online (Sandbox Code Playgroud)

组件.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
}
Run Code Online (Sandbox Code Playgroud)

除了语法差异之外,方法 1 和方法 2 没有任何区别。好的!那是注射部分!

问题二:如何进行店间沟通?(尽量避免)

现在我知道一个好的设计可以让商店保持独立,减少耦合。但是以某种方式考虑一种情况,UserStore如果更改了某个变量,我希望变量 in发生AuthStore 变化。使用Computed. 这种方法对于上述两种方法都是通用的

授权商店.js

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

我希望这对社区有所帮助。更详细的讨论可以参考我在Github上提出问题


She*_*tor 5

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

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>

Run Code Online (Sandbox Code Playgroud)

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

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

回答关于不注入整个商店的问题,您可能会受益于mapperFunction(例如mapStateToProps在redux中)文档

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

}
Run Code Online (Sandbox Code Playgroud)

  • 显然,`rootStore`不为空并且包含一些功能。从关注点分离的最佳实践来看,最好让bankAccountStore和authStore知道rootStore(这将允许他们进行通信),而不是让他们彼此知道。因此,“ rootStore”可能扮演总线的角色,以允许其他存储进行通信。 (2认同)
  • 我要指出的主要目标是-跨商店通信而不是第三商店,而不是直接通信,因为这将使您更好地将商店彼此隔离。我不知道您的应用程序的细节,但是这是一个开发过程,您看到某些东西应该以另一种方式工作-重构。是的,这是开销,但是,如果您的疮彼此依赖,那么当您不得不重构或去除它们时,请预料会有大麻烦。如果这可能不适用于拥有2家商店的应用程序,但是如果您拥有20家商店,那么这很重要。 (2认同)