Skip to content
This repository was archived by the owner on Dec 31, 2020. It is now read-only.
This repository was archived by the owner on Dec 31, 2020. It is now read-only.

Add support for unstable_batchedUpdates when used with react-dom / react-native #153

@gsabanov

Description

@gsabanov

The issue:
I suspect mobx-react-lite observer is handling actions/transactions and subsequent re-rendering differently to mobx-react. I don't know if the behaviour is intended and i am doing something wrong, or if its a bug so i would like to clarify this.

Expected behaviour (the mobx-react way):

  • When an action is modifying the state of one or more models, all changes should be executed before an update (and re-render) is triggered on any affected components
export const ParentModel = types.model({
    title: "Parent",
    toggler: false,
    date: "",
    child: types.optional(ChildModel, {})
}).actions(self => ({
    toggleWithSideEffect(){
        self.child.date = new Date().toString();
        self.date = new Date().toString();
        self.toggler = !self.toggler; 
        // no rendering should have been done until this point  
        console.log("i toggle")
    },
}));

Actual behavior (the mobx-react-lite way)

  • Certain combinations of state modifications cause updates to the state and re-render components in the middle of an action execution (transaction)
export const ParentModel = types.model({
    title: "Parent",
    toggler: false,
    date: "",
    child: types.optional(ChildModel, {})
}).actions(self => ({
    toggleWithSideEffect(){
        // child component referencing this value gets re-rendered after this statement
        self.child.date = new Date().toString();       
        self.date = new Date().toString();
        self.toggler = !self.toggler;
        // no rendering should have been done until this point
        console.log("i toggle")        
    },
}));

I created a (misspelled) repo that demonstrates the issue.

If you run the app in that repo, clicking on the toggle button will work the first time, but will crash the second time because the child model is using a computed value dependent on the toggler value in the parent model, that becomes null on the second iteration, and the child component re-renders before the parent. Running the same code with mobx-react observer behaves as expected, the child component doesn't even try to render when toggler is false.

The issue got weirder while i was composing the repo to test this behaviour.
The idea was to have two react apps next to each other, one with mobx-react one with mobx-react-lite and compare the difference, but loading mobx-react next to mobx-react-lite seems to correct the behaviour, even by just referencing a component that uses the mobx-react observer, see here
I threw in a useContext hook in my test as well to make sure the mobx-react observer isn't overwriting the mobx-react-lite observer when referenced.
Its as if loading mobx-react next to mobx-react-lite enchances/corrects transactional behavior of mobx-react-lite.

The example uses mobx-state-tree, but i was able to produce the same error with a couple of regular mobx nested models.

Here are two branches of the same repo with almost identical code, one with mobx-react and one with mobx-react-lite.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions