Package detail

mobx-react-lite

mobxjs7.1mMIT4.1.0

Lightweight React bindings for MobX based on React 16.8+ and Hooks

mobx, mobservable, react-component, react

readme

mobx-react-lite

CircleCI Coverage Status NPM downloadsMinzipped size Discuss on Github View changelog

This is a lighter version of mobx-react which supports React functional components only and as such makes the library slightly faster and smaller (only 1.5kB gzipped). Note however that it is possible to use <Observer> inside the render of class components. Unlike mobx-react, it doesn't Provider/inject, as useContext can be used instead.

Compatibility table (major versions)

mobx mobx-react-lite Browser
6 3 Modern browsers (IE 11+ in compatibility mode)
5 2 Modern browsers
4 2 IE 11+, RN w/o Proxy support

mobx-react-lite requires React 16.8 or higher.

User Guide 👉 https://mobx.js.org/react-integration.html


API reference ⚒

observer<P>(baseComponent: FunctionComponent<P>): FunctionComponent<P>

The observer converts a component into a reactive component, which tracks which observables are used automatically and re-renders the component when one of these values changes. Can only be used for function components. For class component support see the mobx-react package.

<Observer>{renderFn}</Observer>

Is a React component, which applies observer to an anonymous region in your component. <Observer> can be used both inside class and function components.

useLocalObservable<T>(initializer: () => T, annotations?: AnnotationsMap<T>): T

Creates an observable object with the given properties, methods and computed values.

Note that computed values cannot directly depend on non-observable values, but only on observable values, so it might be needed to sync properties into the observable using useEffect (see the example below at useAsObservableSource).

useLocalObservable is a short-hand for:

const [state] = useState(() => observable(initializer(), annotations, { autoBind: true }))

enableStaticRendering(enable: true)

Call enableStaticRendering(true) when running in an SSR environment, in which observer wrapped components should never re-render, but cleanup after the first rendering automatically. Use isUsingStaticRendering() to inspect the current setting.


Deprecated APIs

useObserver<T>(fn: () => T, baseComponentName = "observed", options?: IUseObserverOptions): T (deprecated)

This API is deprecated in 3.*. It is often used wrong (e.g. to select data rather than for rendering, and <Observer> better decouples the rendering from the component updates

interface IUseObserverOptions {
    // optional custom hook that should make a component re-render (or not) upon changes
    // Supported in 2.x only
    useForceUpdate: () => () => void
}

It allows you to use an observer like behaviour, but still allowing you to optimize the component in any way you want (e.g. using memo with a custom areEqual, using forwardRef, etc.) and to declare exactly the part that is observed (the render phase).

useLocalStore<T, S>(initializer: () => T, source?: S): T (deprecated)

This API is deprecated in 3.*. Use useLocalObservable instead. They do roughly the same, but useLocalObservable accepts an set of annotations as second argument, rather than a source object. Using source is not recommended, see the deprecation message at useAsObservableSource for details

Local observable state can be introduced by using the useLocalStore hook, that runs its initializer function once to create an observable store and keeps it around for a lifetime of a component.

The annotations are similar to the annotations that are passed in to MobX's observable API, and can be used to override the automatic member inference of specific fields.

useAsObservableSource<T>(source: T): T (deprecated)

The useAsObservableSource hook can be used to turn any set of values into an observable object that has a stable reference (the same object is returned every time from the hook).

This API is deprecated in 3.* as it relies on observables to be updated during rendering which is an anti-pattern. Instead, use useEffect to synchronize non-observable values with values. Example:

// Before:
function Measurement({ unit }) {
    const observableProps = useAsObservableSource({ unit })
    const state = useLocalStore(() => ({
        length: 0,
        get lengthWithUnit() {
            // lengthWithUnit can only depend on observables, hence the above conversion with `useAsObservableSource`
            return observableProps.unit === "inch"
                ? `${this.length / 2.54} inch`
                : `${this.length} cm`
        }
    }))

    return <h1>{state.lengthWithUnit}</h1>
}

// After:
function Measurement({ unit }) {
    const state = useLocalObservable(() => ({
        unit, // the initial unit
        length: 0,
        get lengthWithUnit() {
            // lengthWithUnit can only depend on observables, hence the above conversion with `useAsObservableSource`
            return this.unit === "inch" ? `${this.length / 2.54} inch` : `${this.length} cm`
        }
    }))

    useEffect(() => {
        // sync the unit from 'props' into the observable 'state'
        state.unit = unit
    }, [unit])

    return <h1>{state.lengthWithUnit}</h1>
}

Note that, at your own risk, it is also possible to not use useEffect, but do state.unit = unit instead in the rendering. This is closer to the old behavior, but React will warn correctly about this if this would affect the rendering of other components.

Observer batching (deprecated)

Note: configuring observer batching is only needed when using mobx-react-lite 2.0. or 2.1.. From 2.2 onward it will be configured automatically based on the availability of react-dom / react-native packages

Check out the elaborate explanation.

In short without observer batching the React doesn't guarantee the order component rendering in some cases. We highly recommend that you configure batching to avoid these random surprises.

Import one of these before any React rendering is happening, typically index.js/ts. For Jest tests you can utilize setupFilesAfterEnv.

React DOM:

import 'mobx-react-lite/batchingForReactDom'

React Native:

import 'mobx-react-lite/batchingForReactNative'

Opt-out

To opt-out from batching in some specific cases, simply import the following to silence the warning.

import 'mobx-react-lite/batchingOptOut'

Custom batched updates

Above imports are for a convenience to utilize standard versions of batching. If you for some reason have customized version of batched updates, you can do the following instead.

import { observerBatching } from "mobx-react-lite"
observerBatching(customBatchedUpdates)

Testing

Running the full test suite now requires node 14+ But the library itself does not have this limitation

In order to avoid memory leaks due to aborted renders from React fiber handling or React StrictMode, on environments that does not support FinalizationRegistry, this library needs to run timers to tidy up the remains of the aborted renders.

This can cause issues with test frameworks such as Jest which require that timers be cleaned up before the tests can exit.

clearTimers()

Call clearTimers() in the afterEach of your tests to ensure that mobx-react-lite cleans up immediately and allows tests to exit.

changelog

mobx-react-lite

4.1.0

Minor Changes

4.0.7

Patch Changes

4.0.6

Patch Changes

4.0.5

Patch Changes

  • 87e5dfb5 #3763 Thanks @mweststrate! - Switched observer implementation from using global to local state version. Fixes #3728

4.0.4

Patch Changes

  • 3ceeb865 #3732 Thanks @urugator! - fix: #3734: isolateGlobalState: true makes observer stop to react to store changes

4.0.3

Patch Changes

4.0.2

Patch Changes

4.0.1

Patch Changes

4.0.0

Major Changes

  • 44a2cf42 #3590 Thanks @urugator! - Components now use useSyncExternalStore, which should prevent tearing - you have to update mobx, otherwise it should behave as previously.
    Improved displayName/name handling as discussed in #3438.

3.4.3

Patch Changes

3.4.2

Patch Changes

3.4.1

Patch Changes

3.4.0

Minor Changes

  • 4c5e75cd #3382 Thanks @iChenLei! - replace the deprecated react type definition with recommended type definition

  • bd4b70d8 #3387 Thanks @mweststrate! - Added experimental / poor man's support for React 18. Fixes #3363, #2526. Supersedes #3005

    • Updated tests, test / build infra, peerDependencies to React 18
    • [breaking icmw upgrading to React 18] Already deprecated hooks like useMutableSource will trigger warnings in React 18, which is correct and those shouldn't be used anymore.
    • [breaking icmw upgrading to React 18] When using React 18, it is important that act is used in unit tests around every programmatic mutation. Without it, changes won't propagate!
    • The React 18 support is poor man's support; that is, we don't do anything yet to play nicely with Suspense features. Although e.g. startTransition basically works, MobX as is doesn't respect the Suspense model and will always reflect the latest state that is being rendered with, so tearing might occur. I think this is in theoretically addressable by using useSyncExternalStore and capturing the current values together with the dependency tree of every component instance. However that isn't included in this pull request 1) it would be a breaking change, whereas the current change is still compatible with React 16 and 17. 2) I want to collect use cases where the tearing leads to problems first to build a better problem understanding. If you run into the problem, please submit an issue describing your scenario, and a PR with a unit tests demonstrating the problem in simplified form. For further discussion see #2526, #3005

3.3.0

Minor Changes

  • 59b42c28 #3282 Thanks @urugator! - support observable(forwardRef(fn)), deprecate observable(fn, { forwardRef: true }), solve #2527, #3267

3.2.3

Patch Changes

3.2.2

Patch Changes

3.2.1

Patch Changes

3.2.0

Patch Changes

  • Updated dependencies [28f8a11d]:
    • mobx@6.1.0

3.1.7

Patch Changes

3.1.6

Patch Changes

3.1.5

Patch Changes

  • 01a050f7 Thanks @FredyC! - Fix use of react-dom vs react-native

    The es folder content is compiled only without transpilation to keep utils/reactBatchedUpdates which exists in DOM and RN versions. The bundled esm is still kept around too, especially the prod/dev ones that should be utilized in modern browser environments.

3.1.4

Patch Changes

  • 8bbbc7c0 Thanks @FredyC! - Fix names of dist files (for real now). Third time is the charm 😅

3.1.3

Patch Changes

3.1.2

Patch Changes

3.1.1

Patch Changes

  • 81a2f865 Thanks @FredyC! - ESM bundles without NODE_ENV present are available in dist folder. This useful for consumption in browser environment that supports ESM Choose either esm.production.min.js or esm.development.js from dist folder.

3.1.0

Minor Changes

  • a0e5fea #329 Thanks @RoystonS! - expose clearTimers function to tidy up background timers, allowing test frameworks such as Jest to exit immediately

Patch Changes

  • fafb136 #332 Thanks @Bnaya! - Introduce alternative way for managing cleanup of reactions. This is internal change and shouldn't affect functionality of the library.

3.0.1

Patch Changes

  • 570e8d5 #328 Thanks @mweststrate! - If observable data changed between mount and useEffect, the render reaction would incorrectly be disposed causing incorrect suspension of upstream computed values

  • 1d6f0a8 #326 Thanks @FredyC! - No important changes, just checking new setup for releases.

Prior 3.0.0 see GitHub releases for changelog