reactjsmobxmobx-reactjsobject

Why does toJS() return an empty object when applied on observable object? - MobX


I am getting an empty object when I do toJS() on an observable object. I am assigning the values to the observableObject after an API call using Object.assign(). Now I am using this observableObject in a computed method of different store as shown in the code below.

class Store {
    @observable observableObject = {};

    Fetch(){
        .....
        APIcall()
        .then((response) => {
            Object.assign(this.observableObject, response.data);
        }).catch(...)
    }
    .....
}

class Store2 {

    @computed get computedValue(){

        // return an non empty {Symbol(mobx administration): ObservableObjectAdministration$$1} object
        console.log(this.rootStore.store1.observableObject);

        // returns True
        console.log(isObservable(this.rootStore.store1.observableObject));

        // return an empty object
        console.log(toJS(this.rootStore.store1.observableObject));

    }
}

I have referred to this issue but couldn't find any help. Find the log of the observableObject below. Can anyone explain the unexpected bheviour of toJS() in mobx.

EDIT: The target field in the log of proxy mobx observable contains all fields but toJS() conversion yields empty object. Here is the sandbox demo

Edit mobx Object.assign + toJS

chrome log of the observableObject


Solution

  • This is just a question of waiting long enough for the API response. In your CodeSandbox, the script exits almost immediately once the API call returns, without waiting for MobX to update anything. If you get lucky it might finish fast enough for you to see some console output, but probably not.

    The trick is to wait for the API, then update the store, then read the computed value from it:

    import { observable, toJS, runInAction, computed } from "mobx";
    import axios from "axios";
    
    class Store {
      @observable observableObject = {};
    }
    
    const store = new Store();
    
    class Store2 {
      @computed get computedVar() {
        return toJS(store.observableObject);
      }
    }
    
    const store2 = new Store2();
    console.log("Object before API call:", store2.computedVar);
    
    axios
      .get("https://jsonplaceholder.typicode.com/todos/1")
      .then(response => {
        runInAction(() => {
          Object.assign(store.observableObject, response.data);
        });
      })
      .then(() => {
        console.log("Object after API call:", store2.computedVar);
      })
      .catch(console.error);