MobX React Lite
mobx-react-lite provides lightweight, performant React bindings specifically designed for functional components and React Hooks, making it a smaller (1.5kB gzipped) and faster alternative to the full `mobx-react` package. It leverages React's modern features, requiring React 16.8 or higher, and offers core functionalities like `observer` for making components reactive, and `useLocalObservable` for managing local observable state within functional components. Unlike its `mobx-react` counterpart, it eschews `Provider`/`inject` in favor of `useContext` for dependency injection. The current stable version is 4.1.1, with recent updates including support for React 19, and its release cadence is closely aligned with MobX and React major version cycles, ensuring compatibility and performance with modern React applications.
Common errors
-
Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
cause Attempting to use a MobX React Hook (e.g., `useLocalObservable`, `useContext`) outside of a functional React component, or violating other React Hooks rules.fixEnsure all MobX React Hooks are called within a functional component, and follow the Rules of Hooks (e.g., call them at the top level, not in loops, conditions, or nested functions). -
MyComponent is not re-rendering when observable state changes.
cause The functional component or a part of its render tree is not wrapped with `observer` or `<Observer>`, preventing MobX from automatically reacting to state changes.fixWrap your functional component with `observer` (e.g., `export const MyComponent = observer(() => { ... });`) or use `<Observer>{() => ...}</Observer>` around the reactive part of your render function. -
TypeError: Cannot read properties of undefined (reading 'someProperty') inside an observable store.
cause The `this` context inside a MobX action or getter within `useLocalObservable` might be unbound if `autoBind: true` is not explicitly set or the function is defined in a way that loses `this`.fix`useLocalObservable` by default sets `autoBind: true`. Ensure your initializer functions and actions are defined correctly, often as arrow functions or using the concise method syntax in an object literal, so `this` correctly refers to the observable object. If explicitly creating the observable with `observable()`, remember to pass `{ autoBind: true }` in options.
Warnings
- breaking mobx-react-lite requires React 16.8 or higher due to its reliance on React Hooks. Older React versions are not supported.
- deprecated The `useObserver` hook is deprecated since mobx-react-lite v3.0.0. Its usage is often incorrect, and the `<Observer>` component provides better decoupling and clarity.
- deprecated The `useLocalStore` hook is deprecated in favor of `useLocalObservable` since mobx-react-lite v3.0.0. While similar, `useLocalObservable` offers clearer semantics and improved TypeScript inference.
- gotcha This package is designed exclusively for React functional components. For class components, you must use the `mobx-react` package. Using `observer` from `mobx-react-lite` on a class component will not work as expected.
- gotcha In server-side rendering (SSR) environments, `observer` wrapped components should not re-render after the initial pass. Failing to configure this can lead to memory leaks or incorrect behavior.
Install
-
npm install mobx-react-lite -
yarn add mobx-react-lite -
pnpm add mobx-react-lite
Imports
- observer
const observer = require('mobx-react-lite').observer;import { observer } from 'mobx-react-lite'; - Observer
import Observer from 'mobx-react-lite/Observer';
import { Observer } from 'mobx-react-lite'; - useLocalObservable
import { useLocalStore } from 'mobx-react-lite';import { useLocalObservable } from 'mobx-react-lite';
Quickstart
import React from 'react';
import ReactDOM from 'react-dom/client';
import { observer, useLocalObservable } from 'mobx-react-lite';
const Timer = observer(() => {
const store = useLocalObservable(() => ({
secondsPassed: 0,
increment() {
this.secondsPassed++;
},
reset() {
this.secondsPassed = 0;
},
get formattedTime() {
return `Seconds: ${this.secondsPassed}`;
}
}));
React.useEffect(() => {
const handle = setInterval(() => store.increment(), 1000);
return () => clearInterval(handle);
}, [store]);
return (
<div>
<h1>MobX Timer</h1>
<p>{store.formattedTime}</p>
<button onClick={() => store.reset()}>Reset</button>
</div>
);
});
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Timer />);