Mobx: How could I communicate between two stores?

Created on 16 Jun 2016  ยท  6Comments  ยท  Source: mobxjs/mobx

Think like that:
I have two components, each of them have a standlone store, how could I communicate between them, e.g.: Component Foo with Store A, Component Bar with Store B, How could I dispatcher a action in Foo to change a observable state in Store B?

โ” question

Most helpful comment

@spion I actually did some test and it works fine:

export class RootStore {
    public ui: UIStore;
    public todoList: TodoListStore;
    public auth: AuthStore;

    constructor() {
        this.todoList = new TodoListStore(this);
        this.auth = new AuthStore(this);
        this.ui = new UIStore(this);
    }
}

export class AuthStore {
    @observable loggedIn = false;

    constructor(public root: RootStore) {}
}

export class UIStore {
    @observable loadingTask = false;

    constructor(public root: RootStore) {
        autorun(() => {
            // tslint:disable-next-line:no-console
            console.log('UI sees logged in changed', root.auth.loggedIn);
            // tslint:disable-next-line:no-console
            console.log('UI sees loading in changed', root.todoList.loading);
            this.loadingTask = root.auth.loggedIn && root.todoList.loading;
        });
    }
}

export class TodoListStore {

    @observable loading = false;

    @observable todos: TodoItem[] = [
        { id: '1', title: 'first task', finished: false },
        { id: '2', title: 'second task', finished: true }
    ];

    @computed get unfinishedTodoCount() {
        return this.todos.filter(todo => !todo.finished).length;
    }

    @action
    async add() {
        this.todos.push({
            id: Date.now().toString(),
            title: Date.now().toString(),
            finished: false
        });
    }

    constructor(public root: RootStore) { }
}

export class TodoItem {
    id: string;
    @observable title: string;
    @observable finished: boolean;
}

Cross stores autorun works correctly so it should not be a problem.

All 6 comments

You can just give A a reference to B and invoke it's actions? But maybe I don't understand your question correctly, in that case could you explain your problem with some code?

Closed for inactivity, feel free to re-open if anything is unclear

@mweststrate in docs it suggests we have multi stores like UI & Domain. So now domain action shall trigger UI state to update, how should domain action access UI state or action? On the other hand, if there are 4, 5, 6 stores the action network will become a disaster I guess?

Is there a way to subscribe other stores' state?

UI subscribes to Domain's state in reactive way? For both @observable and @compute

It would be helpful to understand the issue if there is a concrete example

@spion I actually did some test and it works fine:

export class RootStore {
    public ui: UIStore;
    public todoList: TodoListStore;
    public auth: AuthStore;

    constructor() {
        this.todoList = new TodoListStore(this);
        this.auth = new AuthStore(this);
        this.ui = new UIStore(this);
    }
}

export class AuthStore {
    @observable loggedIn = false;

    constructor(public root: RootStore) {}
}

export class UIStore {
    @observable loadingTask = false;

    constructor(public root: RootStore) {
        autorun(() => {
            // tslint:disable-next-line:no-console
            console.log('UI sees logged in changed', root.auth.loggedIn);
            // tslint:disable-next-line:no-console
            console.log('UI sees loading in changed', root.todoList.loading);
            this.loadingTask = root.auth.loggedIn && root.todoList.loading;
        });
    }
}

export class TodoListStore {

    @observable loading = false;

    @observable todos: TodoItem[] = [
        { id: '1', title: 'first task', finished: false },
        { id: '2', title: 'second task', finished: true }
    ];

    @computed get unfinishedTodoCount() {
        return this.todos.filter(todo => !todo.finished).length;
    }

    @action
    async add() {
        this.todos.push({
            id: Date.now().toString(),
            title: Date.now().toString(),
            finished: false
        });
    }

    constructor(public root: RootStore) { }
}

export class TodoItem {
    id: string;
    @observable title: string;
    @observable finished: boolean;
}

Cross stores autorun works correctly so it should not be a problem.

Was this page helpful?
0 / 5 - 0 ratings