intermediate
Actions
Group intentional mutations so observable changes stay explicit, traceable, and batched.
Actions bundle intentional state changes. They batch notifications and show up clearly in MobX traces. `makeAutoObservable` treats methods as actions; use `runInAction` for async continuations after `await`.
import { makeAutoObservable, runInAction } from 'mobx';
class UserStore {
user = null;
loading = false;
constructor() {
makeAutoObservable(this);
}
async load(id) {
this.loading = true;
const data = await fetchUser(id);
runInAction(() => {
this.user = data;
this.loading = false;
});
}
}
Without `runInAction`, mutations after await may occur outside an action context and warn in strict mode.
The trade-off is batched, traceable mutations versus discipline to route all writes through actions.
On interviews: why async needs runInAction; contrast with Redux dispatching fulfilled actions.
Common pitfalls: mutating in components instead of store methods, forgotten runInAction after fetch, and actions that also trigger unrelated side effects (prefer reactions).
Checklist:
- Public methods mutate store state.
- runInAction after await boundaries.
- Keep actions focused on state transitions.
- Log/trace actions in dev for debugging.