mobxjs / mobx-react

React bindings for MobX
https://mobx.js.org/react-integration.html
MIT License
4.85k stars 350 forks source link

observer does not re-render components in React Native #907

Closed saeid85 closed 3 years ago

saeid85 commented 3 years ago

Hi, I aim to use Mobx (v6.0.0) & mobx-react (v7.0.0) in a React Native (v0.63.0) project. I have created a store file based on Mobx documentation but after changing an observable attribute, the observer component does not re-render.

Mobx store:

class TestStore {
  textVisibility = false;

  constructor() {
    makeObservable(this, {
      textVisibility: observable,
      isTextVisible: computed,
      toggleText: action
    });
  }

  get isTextVisible() {
    return this.textVisibility;
  }

  toggleText() {
    this.textVisibility = !this.textVisibility;
  }
}

const testStore = new TestStore();

React Native component

import React from "react";
import { observer } from "mobx-react";
import { Text, TouchableOpacity, View } from "react-native";
import testStore from "@stores/TestStore";

const Sample = observer((props) => (
  <View>
    <TouchableOpacity onPress={testStore.toggleText}>
      <Text>Test Mobx</Text>
    </TouchableOpacity>

    {testStore.isTextVisible && (
    <Text>observer is working</Text>
    )}

  </View>
));

export default Sample;
mweststrate commented 3 years ago

Your getter uses uppercase TextVisibility. Tip: use a typechecker 😉

On Sun, 11 Oct 2020, 14:30 Saeid Saberi, notifications@github.com wrote:

Hi, I aim to use Mobx (v6.0.0) & mobx-react (v7.0.0) in a React Native (v0.63.0) project. I have created a store file based on Mobx documentation but after changing an observable attribute, the observer component does not re-render.

Mobx store:

class TestStore { textVisibility = false;

constructor() { makeObservable(this, { textVisibility: observable, isTextVisible: computed, toggleText: action }); }

get isTextVisible() { return this.TextVisibility; }

toggleText() { this.textVisibility = !this.textVisibility; }} const testStore = new TestStore();

React Native component

import React from "react";import { observer } from "mobx-react";import { Text, TouchableOpacity, View } from "react-native";import testStore from "@stores/TestStore"; const Sample = observer((props) => (

Test Mobx {testStore.isTextVisible && ( Saeid Saberi when observer works )} )); export default Sample; — You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub , or unsubscribe .
saeid85 commented 3 years ago

Thanks for the response. Actually this is not the real code & I just publish a sample code to demonstrate what I mean. In the real project I use typechecker.

skillful-alex commented 3 years ago

I have a similar question, so I decided not to open a new issue, but to ask in this one.

I am trying to create a react application using mobx and typescript. But it doesn't work.

I expect the timer to count the seconds. And I see that the event happens and updates the counter. But the component is not rerender. What am I doing wrong?

import React from "react";
import { observable, action } from "mobx";
import { observer, inject, Provider } from "mobx-react";

export class TestStore {
    @observable timer = 0;

    @action timerInc = () => {
        this.timer += 1;
    };
}

interface IPropsTestComp {
    TestStore?: TestStore;
}

@inject("TestStore")
@observer
export class TestComp extends React.Component<IPropsTestComp> {
    constructor(props: IPropsTestComp) {
        super(props);
        setInterval(() => {
            this.props.TestStore!.timerInc();
        }, 1000);
    }

    render() {
        return <div>{this.props.TestStore!.timer}</div>;
    }
}

export class TestApp extends React.Component {
    render() {
        return <Provider TestStore={new TestStore()}>
            <TestComp />
        </Provider>
    }
}

"mobx": "^6.0.1", "mobx-react": "^7.0.0", "react": "^16.13.1",

Updated: I was helped on the stackoverflow . Working code:

import { makeAutoObservable } from "mobx";

export class TestStore {
    timer = 0;

    constructor() {
      // Don't need decorators now, just this call
      makeAutoObservable(this);
    }

    timerInc = () => {
        this.timer += 1;
    };
}
mweststrate commented 3 years ago

Assuming MobX 6, you will need to call makeObservable in the constructor: https://mobx.js.org/enabling-decorators.html

On Thu, Oct 15, 2020 at 8:39 AM Alex Nebotov notifications@github.com wrote:

I have a similar question, so I decided not to open a new issue, but to ask in this one.

I am trying to create a react application using mobx and typescript. But it doesn't work.

I expect the timer to count the seconds. And I see that the event happens and updates the counter. But the component is not rerender. What am I doing wrong?

import React from "react"; import { observable, action } from "mobx"; import { observer, inject, Provider } from "mobx-react";

export class TestStore { @observable timer = 0;

@action timerInc = () => {
    this.timer += 1;
};

}

interface IPropsTestComp { TestStore?: TestStore; }

@inject("TestStore") @observer export class TestComp extends React.Component { constructor(props: IPropsTestComp) { super(props); setInterval(() => { this.props.TestStore!.timerInc(); }, 1000); }

render() {
    return <div>{this.props.TestStore!.timer}</div>;
}

}

export class TestApp extends React.Component { render() { return <Provider TestStore={new TestStore()}>

    </Provider>
}

}

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/mobxjs/mobx-react/issues/907#issuecomment-708963250, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAN4NBDD3VYLE3CDZK5GYX3SK2RLFANCNFSM4SLYYMVQ .

saeid85 commented 3 years ago

@skillful-alex Mobx 6 works fine with React, but when it comes to React Native.... My issue is how to use Mobx6 in a React Native project!

mweststrate commented 3 years ago

React versus React Native should be quite irrelevant from MobX perspective. But without any more accurate information / minimal reproduction we cannot be of any further assistance.

iiagodias commented 3 years ago

same problem

iiagodias commented 3 years ago

As I understand it, this is the native version of React.

mweststrate commented 3 years ago

same solution

iiagodias commented 3 years ago

I found the solution, you just have to declare the action functions as follows:

toggleText = () => {
    this.textVisibility = !this.textVisibility;
}

Final:

class TestStore {
  textVisibility = false;

  constructor() {
    makeObservable(this, {
      textVisibility: observable,
      isTextVisible: computed,
      toggleText: action
    });
  }

  get isTextVisible() {
    return this.textVisibility;
  }

  toggleText = () => {
    this.textVisibility = !this.textVisibility;
  }
}

const testStore = new TestStore();