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

前端 未结 3 1892
南方客
南方客 2021-02-15 10:54

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:

<
相关标签:
3条回答
  • 2021-02-15 11:13

    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)}
    
    0 讨论(0)
  • 2021-02-15 11:23

    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';
    }
    
    0 讨论(0)
  • 2021-02-15 11:30

    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'
    
    0 讨论(0)
提交回复
热议问题