mrkeyoor.com_
Wed 23 Sept 00:34 UTC
npmWeb Frontendupdated 22 Sept 2026

mobx-react-lite review

Mobx-react-lite 5.0.3 connects MobX 7 observables to React 18 and 19 function components. observer records observable values read during render and subscribes that component to those values; Observer creates the same tracking boundary around a render callback, and useLocalObservable creates component-owned MobX state. The package excludes class-component observation and the old Provider/inject API. Version 5 removed deprecated hooks and manual batching helpers, while 5.0.3 adds a Node export condition that routes Node and Bun to the CommonJS entry chosen for the environment. Our browser build measured 52.6 KB minified with its peer packages present, so this is an architectural choice rather than a tiny component helper.

Verdict

Mobx-react-lite 5.0.3 installed in 1.3 seconds and produced a 15.8 KB gzipped full-import bundle in our sandbox, with bundled types and no audit findings. It fits teams already committed to MobX 7; a React app with only shallow local state should stay with built-in hooks or compare a selector-based store.

We installed it

Lab card: what happened when we installed mobx-react-liteScreenshot of mobx-react-lite documentation
Install✓ · 1.3s3 packages on disk · 6 MB
ImportESM import works · require() works · CommonJS package with exports map
Browser15.8 KBgzipped (52.6 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does mobx-react-lite install cleanly?

Yes. In a fresh container with an empty cache, npm install mobx-react-lite finished in 1 seconds, leaving 3 packages and 6 MB on disk. npm audit reported no known vulnerabilities.

How much does mobx-react-lite add to a browser bundle?

15.8 KB gzipped (52.6 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does mobx-react-lite work with both ESM and CommonJS?

Yes. Both import 'mobx-react-lite' and require('mobx-react-lite') worked in Node 22 in our run. The package is published as CommonJS with an exports map.

Does mobx-react-lite include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

mobx-react-lite or zustand: which should you use?

zustand: Use it for hook-based stores with explicit selectors and less commitment to observable classes. Mobx-react-lite 5.0.3 installed in 1.3 seconds and produced a 15.8 KB gzipped full-import bundle in our sandbox, with bundled types and no audit findings.

When should you not use mobx-react-lite?

Class components must observe state. The package README supports function components only and directs class users to mobx-react.

API stability3/5The main observer contract remains recognizable, and version 5 keeps a short public set centered on observer, Observer, useLocalObservable, enableStaticRendering, and isUsingStaticRendering. Its major migration is still large: MobX 7 and React 18 became the floor, old local-state hooks and static-rendering names disappeared, manual batching exports were removed, and MobX 7 requires native Proxy behavior. Version 5.0.3 also adjusts conditional exports for Node and Bun, so package resolution remains part of compatibility testing.
Docs5/5The package README has an exact MobX, binding-major, React, and browser compatibility table, lists every v5 removal and replacement, documents SSR and test timer cleanup, and defines the supported hooks and components. The longer React guide covers late dereferencing, Context stores, local-state tradeoffs, render callbacks, third-party boundaries, forwarded refs, HOC order, prop synchronization, autorun disposal, names in DevTools, and hook linting. Those examples address the places where automatic dependency tracking usually surprises React developers.
Maintenance5/5npm published 5.0.3 on 2026-08-19 with a conditional-export performance fix, and GitHub recorded a monorepo push on 2026-08-24. The unarchived MobX repository has 28,207 stars and reports 56 open issues and pull requests across core and all packages. Version 5 shipped alongside MobX 7, removed obsolete batching paths, and documents its migration. Keeping the React binding in the core monorepo also lets peer compatibility and release changes land together.
Ecosystem5/5The npm endpoint counted 4,025,775 downloads in the latest completed week. MobX provides observable objects, computed values, actions, reactions, dependency inspection, and debugging utilities, while mobx-react-lite supplies React 18, React 19, SSR, and React Native entries. Class bindings remain available through mobx-react. The ecosystem is mature, but integrations built around immutable snapshots or shallow reference checks often need explicit projection before observable collections cross their boundary.

Use it if

  • The application already uses MobX 7 domain stores and needs React components to subscribe to values they read.
  • Function components render deep, computed, or shared mutable models that would make handwritten selectors noisy.
  • A render callback inside a third-party component needs its own Observer tracking boundary.
  • The same binding must cover React 18 or 19, SSR static rendering, and React Native package conditions.
Skip it if

Setup reality

We installed mobx-react-lite 5.0.3 in a fresh unprivileged Node 22 Bookworm sandbox. npm completed in 1.3 seconds and left 3 packages using 6 MB on disk. The package is 404 KB unpacked, declares 0 direct dependencies and 2 peers, and npm audit found 0 known vulnerabilities. Both require() and ESM import worked through its exports map, and TypeScript declarations are bundled. Our browser build measured 52.6 KB minified and 15.8 KB gzipped.

Install compatible peers explicitly: MobX 7 and React 18 or 19. There are no native addons, credentials, or config files. Version 5 removed useObserver, useLocalStore, useAsObservableSource, useStaticRendering, batching imports, observerBatching, and isObserverBatched. Replace them with observer, Observer, useLocalObservable, and enableStaticRendering. Version 5.0.3's node condition directs Node and Bun to the environment-selected CommonJS build, reducing mixed import and require surprises.

Every component that reads observable data must be wrapped with observer. A wrapped parent does not subscribe an unwrapped child to values the child reads. Dereference observable properties inside the tracked component, and pass a plain projection to third-party widgets that are not observers. observer already applies React memo. Named functions inside observer produce clearer DevTools names and avoid hook-lint confusion around anonymous wrapper expressions.

Call enableStaticRendering(true) during server initialization so SSR does not retain reactions after its one render. On test runtimes without FinalizationRegistry, aborted React renders can leave cleanup timers; clearTimers in afterEach handles fake-timer and open-handle failures. useLocalObservable creates its object once, so later prop changes do not update computed dependencies unless an effect copies the prop into observable state. Keep Context provider store identity stable and mutate the store itself.

Patterns

Track observable reads during render observe-function-component

import { makeAutoObservable } from 'mobx';
import { observer } from 'mobx-react-lite';

class CounterStore {
  count = 0;
  constructor() { makeAutoObservable(this); }
  increment() { this.count += 1; }
}
const counter = new CounterStore();

export const Counter = observer(function Counter() {
  return <button onClick={() => counter.increment()}>{counter.count}</button>;
});

A named function gives React DevTools a useful label and lets hook linting see the component inside observer.

Read observable props inside the observer dereference-observable-late

import { observer } from 'mobx-react-lite';

export const TodoRow = observer(function TodoRow({ todo }) {
  return (
    <label>
      <input type="checkbox" checked={todo.done} onChange={() => todo.toggle()} />
      {todo.title}
    </label>
  );
});

Pass the observable object down. Reading todo.title in an unwrapped parent would subscribe the wrong render boundary.

Share a store with React Context provide-store-through-context

import { createContext, useContext } from 'react';
import { observer } from 'mobx-react-lite';

const StoreContext = createContext(null);
function useStore() {
  const store = useContext(StoreContext);
  if (!store) throw new Error('StoreContext is missing');
  return store;
}
export const UserName = observer(function UserName() {
  return <span>{useStore().session.userName}</span>;
});

Version 5 has no MobX Provider or inject export. Keep the Context value stable while observable fields change.

Create computed local state create-local-observable

import { observer, useLocalObservable } from 'mobx-react-lite';

export const Quantity = observer(function Quantity() {
  const state = useLocalObservable(() => ({
    value: 1,
    get doubled() { return this.value * 2; },
    increment() { this.value += 1; },
  }));
  return <button onClick={state.increment}>{state.value} / {state.doubled}</button>;
});

Use React useState for simple local flags. useLocalObservable pays off when local state is deep, computed, or passed to observer children.

Update a prop-backed computed value sync-prop-into-observable

import { useEffect } from 'react';
import { observer, useLocalObservable } from 'mobx-react-lite';

export const Total = observer(function Total({ offset }) {
  const state = useLocalObservable(() => ({
    total: 0,
    offset,
    setOffset(value) { this.offset = value; },
    get adjusted() { return this.total - this.offset; },
  }));
  useEffect(() => state.setOffset(offset), [offset, state]);
  return <output>{state.adjusted}</output>;
});

React props are not observable. The initializer runs once, so an effect must copy later offset values into local observable state.

Observe a third-party render callback track-render-callback

import { Observer } from 'mobx-react-lite';

function GridCell({ todo }) {
  return (
    <Grid renderCell={() => (
      <Observer>{() => <span>{todo.title}</span>}</Observer>
    )} />
  );
}

The callback runs during Grid's render, outside its parent's tracked function. Observer places tracking where todo.title is read.

Project observables for a plain component pass-plain-third-party-data

import { observer } from 'mobx-react-lite';

export const Results = observer(function Results({ store }) {
  const rows = store.results.map((item) => ({ id: item.id, title: item.title }));
  return <ThirdPartyGrid rows={rows} />;
});

A component that is not an observer will not subscribe to nested observable changes. A small projection avoids copying an entire graph with toJS.

Disable subscriptions during SSR enable-static-ssr

import { enableStaticRendering } from 'mobx-react-lite';

enableStaticRendering(typeof window === 'undefined');

Run this during environment startup. Server renders should clean up after one pass instead of retaining component reactions.

Tie autorun to component lifetime dispose-autorun

import { autorun } from 'mobx';
import { useEffect } from 'react';

function useDraftSaver(draft) {
  useEffect(() => autorun(() => {
    localStorage.setItem('draft', draft.text);
  }), [draft]);
}

autorun returns a disposer. Returning it from useEffect removes the MobX reaction when the component unmounts or draft changes.

Clear fallback timers after tests clear-test-cleanup-timers

import { afterEach } from 'vitest';
import { clearTimers } from 'mobx-react-lite';

afterEach(() => {
  clearTimers();
});

This matters on runtimes without FinalizationRegistry, where aborted renders can leave cleanup timers visible to open-handle checks.

Alternatives

PackageRegistryPick it when
zustandnpmUse it for hook-based stores with explicit selectors and less commitment to observable classes.
jotainpmUse it when application state composes naturally from small atoms and React-first dependency tracking.
mobx-reactnpmUse it when the same MobX application must observe React class components or use the supported observer decorator.

More web frontend guides

postcss · react · react-dom · tailwindcss · htmlparser2 · tailwind-merge · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.