1
votes

I can't make React re-render with MobX. I'm setting up everything as per the documentation. My class contains action and observable decorators. I tried hooking up the React component with useObserver hook or observer HOC and it simply won't re-render.

Snippet:

import React from "react";
import ReactDOM from "react-dom";
import { action, observable } from "mobx";
import { observer, useObserver } from "mobx-react-lite";

class Timer {
  @observable secondsPassed: number = 0;

  @action increaseTimer() {
    console.log("here");
    this.secondsPassed += 1;
  }
}

const myTimer = new Timer();

setInterval(() => {
  myTimer.increaseTimer();
}, 1000);

const TimerView = ({ timer }: { timer: Timer }) => {
  return useObserver(() => <div>{timer.secondsPassed}</div>);
};

ReactDOM.render(<TimerView timer={myTimer} />, document.body);

https://codesandbox.io/s/minimal-observer-forked-gif4q?file=/src/index.tsx

I'm trying to make it work with decorators, what am I doing wrong?

2
Thank you for the clarification, I had the same issue - Elad Ezra

2 Answers

1
votes

After 4 hours of research. My team's project was using MobX version 4.x and the codebase used decorators as the example above.

BUT

MobX before version 6 encouraged the use of ES.next decorators to mark things as observable, computed and action. However, decorators are currently not an ES standard, and the process of standardization is taking a long time. It also looks like the standard will be different from the way decorators were implemented previously. In the interest of compatibility we have chosen to move away from them in MobX 6, and recommend the use of makeObservable / makeAutoObservable instead.

MobX Documentation

Which means, MobX now requires to declare the class as observable in the constructor using makeObservable(this):

import { makeObservable } from "mobx";

class Timer {
  @observable secondsPassed: number = 0;

  @action increaseTimer() {
    this.secondsPassed += 1;
  }

  // THIS IS IMPORTANT FROM MOBX 6.X ONWARDS
  constructor() {
    makeObservable(this);
  }
}

From the docs:

MobX before version 6 did not require the makeObservable(this) call in the constructor, but because it makes the implementation of decorator simpler and more compatible, it now does. This instructs MobX to make the instances observable following the information in the decorators -- the decorators take the place of the second argument to makeObservable.

For further reading MobX

0
votes

you need to wrap your app with Provider and pass the store as a prop

import { Provider } from 'mobx-react';


ReactDOM.render(
 <Provider {myTimer}> <TimerView timer={myTimer} /> </Provider>,
  document.body
);