React + Mobx: 'this' is null when trying to update the repository

Just get started with Mobx and React and not get the store update. I get an error when I click a button that should update the "me" property:

Store.js:12 Uncaught TypeError: Cannot set property 'me' of null 

My shop:

 import { observable } from 'mobx'; class Store { @observable me; constructor() { this.me = 'test'; } change_me(){ this.me = 'test 1'; console.log(this); // null??? } } const store = new Store(); export default store; 

Component:

 import React from "react"; import { observer } from 'mobx-react'; export default class Layout extends React.Component{ render(){ var store = this.props.store; return( <div> <button onClick={store.change_me}>{store.me}</button> </div> ) } } 

I probably missed some fundamental part of how this works, but I can’t understand.

+3
source share
3 answers

I do not know mobx , but onClick={store.change_me} is a problem because you use the method for the class as a function (without this ). You will need to use something like:

 onClick={event => store.changeMe(event)} 

otherwise, the binding to the store will be lost.

Also possible, but less readable:

 onClick={store.changeMe.bind(store)} 
+1
source

As @Sulthan mentioned, you need to have a method wrapped with another onClick={()=>store.changeMe()} function. The second problem is that you are missing an action decorator for a method that updates the value. Mobx works in such a way that every method that updates properties must be embellished with @action . So, the following problem will fix the problem import {action} from 'mobx ,

 @action change_me(){ this.me = 'test 1'; } 
0
source

Yes, respond to event callbacks with this equal to zero. Since you only onClick method, not store as the context.

Decision

You must set this context yourself. You can do this in the following ways.

Bad practice:

as @Eduard said you can warp it into an arrow function. the Arrow function ensures that the this context remains unchanged in the body of the function:

 <button onClick={() =>store.change_me()}>{store.me}</button> 

You can also use the bind method:

 <button onClick={store.change_me.bind(store)}>{store.me}</button> 

it is basically the same.

Why do they work poorly? on each call to render() these methods are recreated. and can lead to unnecessary unnecessary re-rendering.

Innovate experience

mobx provides an action.bound that wraps the function in the appropriate context:

 @mobx.action.bound change_me(){ this.me = 'test 1'; } 

Alternatively, defining an es6 class allows you to correctly define this context yourself:

 @mobx.action change_me = () => { this.me = 'test 1'; } 

See arrow function. behind the scenes: instead of defining a function / method in the prototype of the store class. the method is created in the constructor , so the context variable this always corresponds to an instance of the class.

so that:

 var a = new Store(); // a.me = 'test' var b = new Store(); // b.me = 'test' a.change_me = b.change_me; // change_me function contains its own this context. a.change_me(); // a.me = 'test' b.me = 'test 1' 
0
source

Source: https://habr.com/ru/post/1260033/


All Articles