MobX Basics
Yiliang Wang
Reactive programming in React
view = f(state)
Once is defined, each time changes, will update automatically
f
state
view
render function
props + useState()
React tracks each setState() call
useState() from ancestors
Reactive programming in MobX React
view = f(state)
Once is defined, each time changes, will update automatically.
f
state
view
render function
props + useState() + observables
useState() from ancestors
- React tracks each setState() call
- Mobx tracks read/write of observables
MobX core concepts
Observables
mutable state
Read
Write
observable
Collect dependencies
Trigger updates
const foo = {
value: 0
};
makeAutoObserverable(foo);
// read foo.value
const value = foo.value;
console.log(value);
// write foo.value
foo.value = 1;MobX core concepts
Reactions
Consumer functions of observables, which automatically run whenever relevant observables change.
const foo = {
value: 0
};
makeAutoObservable(foo);
// register a reaction which uses foo.value
autorun(() => {
const value = foo.value;
console.log(value);
});
// write foo.value
window.setInterval(() => {
foo.value++;
}, 1000);
MobX core concepts
Actions
An action is a function that modifies the state.
const foo = {
value: 0
};
makeAutoObservable(foo);
// register a reaction which uses foo.value
autorun(() => {
const value = foo.value;
console.log(value);
});
// foo.value = 1;
// foo.value = 2;
const updateValue = action(() => {
foo.value = 1;
foo.value = 2;
});
updateValue();
-
They are run inside transactions
- Avoid illegal intermediate state
- Better performance
- This helps to clearly identify where the state updates happen
Why using actions?
Creating observables
- makeAutoObservable(target, overrides?, options?)
import { makeAutoObservable } from "mobx";
class Timer {
secondsPassed = 0;
constructor() {
makeAutoObservable(this);
}
increaseTimer() {
this.secondsPassed += 1;
}
}
const timer = new Timer();import { makeAutoObservable } from "mobx";
function createTimer() {
return makeAutoObservable({
secondsPassed: 0,
increment() {
this.value += 1;
}
})
}
const timer = createTimer();
React integration
import { observer } from "mobx-react-lite"
const MyComponent = observer(props => ReactElement);
Using external state in observer components
import { observer } from "mobx-react-lite";
const myTimer = new Timer();
const TimerView = observer(({ timer }) => <span>Seconds passed: {timer.secondsPassed}</span>);
// Pass myTimer as a prop.
ReactDOM.render(<TimerView timer={myTimer} />, document.body);Option 1: observables can be passed into components as props
Using external state in observer components
import { observer } from "mobx-react-lite";
const myTimer = new Timer();
// or import myTimer from "../store/my-timer";
// No props, `myTimer` is directly consumed from the closure.
const TimerView = observer(() => <span>Seconds passed: {myTimer.secondsPassed}</span>);
ReactDOM.render(<TimerView />, document.body);Option 2: using global variables
Using external state in observer components
import {observer} from 'mobx-react-lite';
import {createContext, useContext} from "react";
const TimerContext = createContext<Timer>();
const TimerView = observer(() => {
// Grab the timer from the context.
const timer = useContext(TimerContext);
return (
<span>Seconds passed: {timer.secondsPassed}</span>
);
});
ReactDOM.render(
<TimerContext.Provider value={new Timer()}
<TimerView />
</TimerContext.Provider>,
document.body
);Option 3: using React context
🥱To be continued
Mobx Basics
By yiliang_wang
Mobx Basics
- 52