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.