I have recently stumbled upon a situation where observable starts behaving just as a normal variable, observable on first render, but further manipulation of it changes its behavior. To explain this scenario, we are going to replicate best practices from React and MobX.

The actual problem occurs once you have an observable variable in one of your viewstores (main viewstore), and want to have that variable’s updated value on every change in another viewstore that doesn’t extend the main viewstore. So, how should we find our way around it so that our observable variable can once again become observable everywhere?


  1. First, we define our observable variable in our main viewstore. This is the object whose value we want in another viewstore. We are going to name it observableObject. Note: this is also the viewstore in which you want to define logic handling observableObject value changes.
@observable observableObject
  1. In the following step, we have to inject our main viewstore into the main page’s template - so that we have access to methods and variables from our main viewstore. Note: since we are following best practices of React and MobX, we are going to have a store that contains logic concerning global needs of the project - named RootStore, through which all communication can happen.
@inject(i => ({
    rootStore: i.rootStore,
    mainViewStore: i.rootStore.mainViewStore
}))
  1. To gain easy access to the observableObject, we will deconstruct items from our main viewstore.
class MainPageTemplate extends Component {
    render() {
		const { observableObject } = this.props.mainViewStore;
		.
		.
		.
  1. Now, in our main page, when rendering a component, we need to pass observableObject as a prop of that component.
return (
	<ComponentOnMainPage observableObject={observableObject} />
	.
	.
	.

This completes the first part of our scenario. Let’s move to the second part where we will make our secondary viewstore observe the same object properly.

  1. First of all, we need to create an observable in our secondary viewstore. Note: just in case something goes wrong, we are going to set its value to null. This will make your debugging easier once you are implementing logic in your main viewstore since you will know its current value.
@observable observableObject = null;
  1. We have come to a part where the actual problem occurs. Your observableObject, if changed in the main viewstore, won’t change in your secondary viewstore - which we are currently editing. Now, we will implement a method in our secondary viewstore that will be called on each render of the page and change the value of observableObject according to its value in the main viewstore.
@action.bound
setObservableObject(value){
    this.observableObject = value;
}
  1. All that is left is to inject our secondary viewstore into our secondary page along with the following:
@inject(i => ({
    rootStore: i.rootStore,
    secondaryViewStore: i.rootStore.secondaryViewStore
}))
  1. deconstructing props. Now, you will notice that our observableObject has actually come from props, and not from our secondary viewstore, which is very important. If we were to use our observableObject from our secondary viewstore - its value wouldn’t change.
class SecondaryPageTemplate extends Component {
    render() {
		const { observableObject } = this.props;
		const { setObservableObject } = this.props.secondaryViewStore;
		.
		.
		.
  1. To finalize the story, we will trigger a method on every render of the secondary page, that method will set secondary viewstore’s observableObject value to our primary viewstore’s observableObject value.
setObservableObject(observableObject);

And that is it. You can now successfully observe the value of our observableObject between two viewstores which do not extend each other.

More articles

Related posts