Search code examples
reactjsmobxmobx-react

MobX React Not re-rendering


I am trying to implement a MobX - React App. But having trouble updating/ re-rendering the value. Store seems to load correctly and it is setting the initial value in the label. But any further value changes are not getting reflected.

OrganisationNameStore store :

import {action, observable} from 'mobx';
import OrganisationName from '../modules/OrganisationName';

export class OrganisationNameStore{
    @observable public orgName: OrganisationName = new OrganisationName();

    @action.bound
    public clear(): void{
        this.orgName = new OrganisationName();
    }

    @action.bound
    public handleTextChange(event: React.FormEvent<HTMLInputElement>) {
        this.orgName.name = event.currentTarget.value;
    }  
}

// Interface is required for TypeScript to be Type safe
export interface IOrganisationNameStore {
    orgName: OrganisationName;
    clear(): void;
    handleTextChange(event: React.FormEvent<HTMLInputElement>): void;
    getOrganisationName(): string;
}

Parent Store file :

import { OrganisationNameStore } from './OrganisationNameStore';

// Have all the stores here
export const stores = {
    organisationNameStore: new OrganisationNameStore(),
};

OrganisationName class :

export default class OrganisationName {
    public name!: string;

    constructor () {
        this.clear = this.clear.bind(this);  
        this.clear();     
    }

    public clear(): OrganisationName {
        this.name = 'Mobx Text 1';            
        return this;
    }
}

Index :

import React from 'react';
import './index.css';
import * as serviceWorker from './serviceWorker';
import ReactDOM from 'react-dom';
import { Provider } from 'mobx-react';
import { stores } from './stores/store';
import App from './App';

ReactDOM.render(
    <Provider {...stores}>
        <App />
    </Provider>
    , document.getElementById('root')    
);

serviceWorker.unregister();

App.tsx File :

import React from 'react';
import './App.css';
import { observer, inject } from 'mobx-react';
import {IOrganisationNameStore} from './stores/OrganisationNameStore'

interface IAppProps /*extends WithStyles<typeof styles> */{
  organisationNameStore?: IOrganisationNameStore // MobX Store

}

@inject('organisationNameStore')
@observer
class App extends React.Component<IAppProps> {
  constructor(props: IAppProps) {
    super(props);
  }

  render() {
    return (
      <div className="App">
        <input
          type="text"
          // value={this.props.organisationNameStore!.orgName.name}
          name="name"
          onChange={this.props.organisationNameStore!.handleTextChange}
        />
        <div>
          <label>{this.props.organisationNameStore!.orgName.name}</label>
        </div>
      </div>
    );
  }
}

export default App;

tsconfig.tsx :

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "outDir": "build/dist",
    "module": "esnext",
    "target": "es5",
    "lib": [
      "es6",
      "dom",
      "esnext.asynciterable"
    ],
    "sourceMap": true,
    "allowJs": true,
    "jsx": "preserve",
    "moduleResolution": "node",
    "rootDir": "src",
    "forceConsistentCasingInFileNames": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitAny": true,
    "importHelpers": true,
    "strictNullChecks": true,
    "suppressImplicitAnyIndexErrors": true,
    "noUnusedLocals": true,
    "allowSyntheticDefaultImports": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "strict": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true
  },
  "exclude": [
    "node_modules",
    "build",
    "scripts",
    "acceptance-tests",
    "webpack",
    "jest",
    "src/setupTests.ts"
  ],
  "include": [
    "src"
  ]
}

.babelrc :

{
    "presets": ["@babel/preset-react"],
    "plugins": [
      "transform-runtime","transform-decorators-legacy"
      // ["@babel/plugin-proposal-decorators", { "legacy": true }],
      // ["@babel/plugin-proposal-class-properties", { "loose": true }]

    ]
  }

There is no console errors.

Expected behavior - I wanted the label value to be updated when ever i type in the input in the App.tsx file.

Please correct me if i am wrong in implementing this?


Solution

  • as mweststrate said here: https://stackoverflow.com/a/39959958/829154

    MobX only converts plain objects automatically to observable objects when assigning them to e.g. an array, because for class instances it might interfere with the internals of that class otherwise.

    See: https://mobxjs.github.io/mobx/refguide/object.html, second bullet

    so you should mark name as @observable in your OrganisationNameStore class.