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

Correct way of Creating multiple stores with mobx and injecting it into to a Component - ReactJs

按照 Mobx 中的建议 documentation 我已经按照以下方式创建了多个商店:

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

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

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

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

以下列方式提供给 App

<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 讨论的结尾做了一个回答。 Link 的答案中提供的讨论

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

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。删除它,不要传递给其他商店。只保留 2 家兄弟店

回答你关于注入不是整个商店的问题,你可能会受益于 mapperFunction(比如 redux 中的 mapStateToPropsdocs here

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

}

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

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

方法一:

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
}

方法二:

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 除了语法差异外没有任何区别。好的!那是注射部分!

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

Now I know a good design keeps stores independent and less coupled. But somehow consider a scenario where I want the variable in UserStore to change if a certain variable in AuthStore is changed. Use Computed. This approach is common for both the above approaches

AuthStore.js

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

I hope this helps the community. For more detailed discussion you can refer to the issue raised by me on Github

在将 RootStore 传递给 Provider 之前直接在 api.js 文件中初始化它有时不是您想要的。 这会使主存储实例 class 更难注入其他 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 中创建新实例 class:

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

export default new RootStore();

Example 1Example 2 相比,更难 access/inject 在应用程序的另一部分存储,如下所述 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));