Правильный способ создания нескольких магазинов с помощью mobx и добавления его в компонент - ReactJs
Как предлагается здесь в документации Mobx, я создал несколько магазинов следующим образом:
class bankAccountStore {
constructor(rootStore){
this.rootStore = rootStore;
}
...
class authStore {
constructor(rootStore){
this.rootStore = rootStore;
}
...
И, наконец, создание корневого хранилища следующим образом. Также я предпочитаю строить детские магазины в конструкторе магазина мастера. Более того, я обнаружил, что иногда моему дочернему хранилищу приходится наблюдать некоторые данные из родительского хранилища, поэтому я передаю их в дочерние конструкторы.
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 в пользовательский компонент?
1 ответ
Я бы порекомендовал вам иметь несколько магазинов, чтобы избежать цепочки магазинов. Как мы делаем в нашем приложении:
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
(лайк mapStateToProps
в редуксе) документы здесь
@inject(stores => ({
someProp: stores.rootStore.someProp
})
)
@observer
class User extends React.Component {
// no props.rootStore here, only props.someProp
}
Этот ответ может быть самоуверенным, но может косвенно помочь сообществу.
После долгих исследований я увидел следующие подходы, используемые на практике многими. Общие методы Имеют корневое хранилище, которое может служить каналом связи между хранилищами.
Вопрос 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;
}
}
}
Я надеюсь, что это помогает сообществу. Для более подробного обсуждения вы можете обратиться к проблеме, поднятой мной на Github
Инициализация вашего RootStore непосредственно в файле api.js перед его передачей провайдеру иногда не является тем, что вам нужно. Это может усложнить внедрение экземпляра класса основного магазина в другие файлы 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));