In MobX how to reference an observable from StoreB that is in StoreA

Viewed 513

I would like to pass only one observable of StoreA to StoreB without passing the full StoreA.

Here is an example, where I pass the user observable in the constructor of TodoStore from the UserStore, but obviously it doesn't update when I change the observable.

So the question is how to do it the cleanest and shortest way, without passing the full reference of the UserStore?

import * as React from "react";
import { render } from "react-dom";
import { observer } from "mobx-react";
import { observable, computed, action } from "mobx";

export class TodoStore {
  @observable public todos: string[] = [ "default" ];
  private user:string;

  constructor(user:string) {
    this.user = user;
  }

  @action.bound
  public addTodo = (todo: string) => {
    this.todos.push(this.user + ": " + todo);
  };
}

export class UserStore {
  @observable public user: string = "zubi";

  @action.bound
  public change = (name: string) => {
    this.user = name;
  };
}

var userStore = new UserStore();
var todoStore = new TodoStore(userStore.user);

@observer
class App extends React.PureComponent {
  public render() {
    return (
      <div>
        <button onClick={e => {todoStore.addTodo("hello" + Math.floor(Math.random() * 1000));}}>
          add message
        </button>
        <button onClick={e => { userStore.change("Eve" + Math.floor(Math.random() * 100),);}}>
          change name
        </button>
        <div>
          {todoStore.todos.map(todo => { return <div key={todo}>{todo}</div>;})}
        </div>
      </div>
    );
  }
}

render(<App />, document.getElementById("root"));

Here you can check the full code: https://codesandbox.io/s/mobx-test-zubi-pf1qn

Thanks a lot!

3 Answers

If you refer to What does MobX react to?

You will learn that mobx tracks property access not values. So you could pass in a specific observable, but it can't be a primitive value.

Make UserStore.user an object, and then you will be able to track it's properties the way you want to (UserStore.user.name) etc.

I found the simplest way so far is something like this:

export class TodoStore {

  @computed get user(): string {return this._user()};

  constructor(private _user: () => string) { }

  // ...

}

// ...

var todoStore = new TodoStore( () => userStore.user );

// ...
Related