I've built a basic counter React app with a simple MobX store. I was able to create an observable MobX status using makeObservable
but for some reason when I try to use makeAutoObservable
I get the error
Cannot read property 'counter' of undefined
How am I using makeAutoObservable
incorrectly?
store
import { makeAutoObservable, makeObservable, action, observable } from "mobx";
class SampleStore {
counter = 0;
constructor(arg) {
makeAutoObservable(this);
// makeObservable(this, {
// counter: observable,
// increment: action.bound,
// decrement: action.bound,
// });
}
increment() {
this.counter++;
return this.counter;
}
decrement() {
this.counter--;
return this.counter;
}
}
export default SampleStore;
useStore hook
import { createContext, useContext } from "react";
import SampleStore from "./SampleStore";
export const store = {
sampleStore: new SampleStore(),
};
export const StoreContext = createContext(store);
export const useStore = () => {
return useContext(StoreContext);
};
provider
import { store, StoreContext } from "./stores";
import Index from "./layout/Index";
function App() {
return (
<StoreContext.Provider value={store}>
<Index />
</StoreContext.Provider>
);
}
export default App;
React component
import { useStore } from "../stores";
import { observer } from "mobx-react";
const Index = (props) => {
const store = useStore();
const {
sampleStore: { counter, increment, decrement },
} = store;
return (
<>
<h1>MobX and React.js example</h1>
<p>{counter}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</>
);
};
export default observer(Index);
It throws because your methods losing context (this
) upon invocation (because you have destructured them).
It was working with makeObservable
because you were using action.bound
which autobinds method to the instance context.
If you want same functionality with makeAutoObservable
you need to use arrow functions, like that:
class SampleStore {
counter = 0;
constructor(arg) {
makeAutoObservable(this);
}
// Make it arrow function
increment = () => {
this.counter++;
return this.counter;
}
// Make it arrow function
decrement = () => {
this.counter--;
return this.counter;
}
}
Alternatively you can also use autoBind
option for makeAutoObservable
:
constructor(arg) {
makeAutoObservable(this, {}, { autoBind: true });
}