score:18
this answer may be opinionated but it may help the community indirectly.
after a lot of research, i saw below approaches used in practice by many. general methods have a root store that can act as a communication channel between stores.
question 1: how to organise stores and inject them into the component?
approach 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
}
approach 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
}
approach 1 and approach 2 doesn't make any difference other than syntax difference. okay! that is the injection part!
question 2: how to have an inter-store communication? (try to avoid it)
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 inauthstore
is changed. usecomputed
. this approach is common for both the above approachesauthstore.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
score:1
initializing your rootstore directly in api.js file before passing it to provider is sometimes not what you want. this can make injecting the instance of main store class harder into other js files:
example 1:
app.js - creates new instance before passing it to provider:
//root store declaration
class rootstore {
constructor() {
...
}
}
const rootstore = new rootstore()
// provide the store to the children
<provider rootstore={rootstore}>
<app />
</provider>
example 2:
rootstore.js - creates new instance directly in rootstore class:
// root store declaration
class rootstore {
constructor() {
...
}
}
export default new rootstore();
example 1
compared to example 2
, makes harder to access/inject the store in another part of the application, like in api.js
described below.
api.js file represents axios wrapper (in my case it handles global loading indicator):
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);
}
)
and using react hooks, you can inject the store that way:
import { observer, inject } from "mobx-react";
const yourcomponent = ({yourstore}) => {
return (
...
)
}
export default inject('yourstore')(observer(yourcomponent));
score:14
i would recommend you to have multiple stores, to avoid chaining of stores. as we do in our application:
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>
in such a manner you can access exactly the store you need, as mostly one store covers one domain instance. still, both sub-stores are able to communicate to rootstore
. set its properties or call methods on it.
if you do not need a cross store communication - you may not need a rootstore
at all. remove it and don't pass to other stores. just keep 2 siblings stores
answering your question on injecting not a whole store, you may benefit from mapperfunction
(like mapstatetoprops
in redux) docs here
@inject(stores => ({
someprop: stores.rootstore.someprop
})
)
@observer
class user extends react.component {
// no props.rootstore here, only props.someprop
}
Source: stackoverflow.com
Related Query
- Correct way of Creating multiple stores with mobx and injecting it into to a Component - ReactJs
- React Convert Div and Table Component Into PDF With Multiple Pages and CSS
- Having difficulty with unit testing MobX observer components with multiple stores injected
- How to combine multiple stores as Root Store in Mobx and get access of in each other's fields and functions
- Correct way to use ref with Next.js for a Link and an <a>?
- How to make multiple HTTP requests with RxJS and merge the response into one payload and map it to another action?
- Correct way to React axios post with UUID and nested object in JSON payload?
- Better use some large or multiple small stores with React and Reflux
- What is the correct way to React Hook Fetch Api and store to Redux and retrieve it with Selector immediately?
- Creating a Redux Observable Epic with multiple API Calls - Passing the results of the first into the second
- React Reflux: Correct way to initiate stores and update dependent components
- Correct way to cancel eventListeners with nextjs, react and flowplayer
- Correct way to update state with react select multiple
- Is there a way to build multiple apps from single one with replacing some assets and components?
- Is there any way to turn a webpage that is styled partially with Javascript into pure HTML and CSS?
- Creating a work hours component - How to useState with multiple values going into an array
- Correct way to push into state array
- Multiple classNames with CSS Modules and React
- Is there any way to see names of 'fields' in React multiple state with React DevTools when using 'useState' hooks
- Proper way to navigate with React Native, Redux, and Navigator
- React i18next and correct way of changing language
- using mobx with react functional components and without decorators
- Correct way (if possible) to store JSX code into a Javascript variable
- Correct way to throttle HTTP calls based on state in redux and react
- React component with Edit Mode and View Mode, is this a correct pattern?
- Best way for internationalization with Gatsby and Strapi
- How is the correct way to have multiple dataProviders in react-admin?
- Multiple Registration Form with redux and react
- What is the correct way of dispatching an action not tied to a component with Redux?
- Reactjs - correct way of inherit props to first level children and nested children
More Query from same tag
- How to access child by the reference of parent in React effectively?
- Possible to run commands after npm start on the same console?
- Import Arabic font to React Material Theme
- onClick executing a function and setState in react
- Multiple Inheritance (Styled Components)
- Please I'm using fetch to get data from an API, but only the JSX return without the products. Api is from: http://fakestoreapi.com/docs
- Setting a state variable has no effect
- Correctly formatting Bootstrap columns? (Offsetting, etc.)
- Getting value from 'time' type input
- onInput event type on TypeScript / React
- React functional components, setState and immutability
- Cannot access pxToRem function in Material-ui for theme
- Cannot access state inside callback
- Using package.json script to run another package.json script
- How to dynamically set State using hooks
- Button is not getting enabled on text input in React?
- React state resetting
- React Native Elements Checkbox
- How to use Redux actions for multi-dimensional object?
- Error: .plugins[3] may only be a two-tuple or three-tuple
- Typescript/React/MaterialUI/JSS project: override CSS for a single React component
- Module not found: Can't resolve 'react-linkedin-login-oauth2'
- Typescript: Type 'Timer' is not assignable to type 'null'
- How to pass array object from select tag and pass values into API?
- Dynamic CSS in typescript - How to access parameter passed to the `useStyles` method
- Most concise way to take props in React
- Modify this yup validation to change max length to 9 if the string does not include a dash
- Import image dynamically in React component
- I get "this.props.comments.map is not a function" or other errors if I click on a photo after deleting a different one in my MERN app
- Objects are not valid as a React child - Text Input