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

随声附和 提交于 2019-12-09 13:34:53

问题


Just getting started with Mobx & React and having trouble getting the store to update. I get error when clicking the button, which should update the 'me' property:

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

My store:

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;

The 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've probably missed some fundamental part of how this works, but can't figure it out.


回答1:


Yes react execute event callbacks with this being null. Since you only give the onClick callback the change_me method and not the store as context.

Solutions

You have to set the this context yourself. you can do this in the following ways

bad practices:

as @Eduard said you can warp it into an arrow function. the Arrow function makes sure the this context stays the same in the function body:

<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>

this does basically the same thing.

Why are they bad practises? on every render() call, these methods are re-created. and can result in extra unnecessary re-renders.

Good practices

mobx provides a action.bound which wraps the function with the proper this context:

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

Alternatively es6 class definition allows you to define the this context properly yourself:

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

See the arrow function. behind the scenes: instead of defining the function/method on the prototype of the Store class. the method is created in the constructor so that the this context variable always matches the 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'



回答2:


I don't know mobx but onClick={store.change_me} is a problem because you are using a method on a class as a function (without this). You will have to use use something like:

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

otherwise the binding to store is lost.

Also possible but less readable:

onClick={store.changeMe.bind(store)}



回答3:


As @Sulthan mentioned, you need to have the method wrapped by another function onClick={()=>store.changeMe()}. Second issue is you are missing action decorator for the method which updating the value. Mobx works in a way where every method which will update properties, it need to be decorated by @action. So following will fix the issue import {action} from 'mobx,

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


来源:https://stackoverflow.com/questions/40702028/react-mobx-this-is-null-when-trying-to-update-store

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!