1 | # mobx-react-lite
|
2 |
|
3 | [![CircleCI](https://circleci.com/gh/mobxjs/mobx-react-lite.svg?style=svg)](https://circleci.com/gh/mobxjs/mobx-react-lite)
|
4 | [![Coverage Status](https://coveralls.io/repos/github/mobxjs/mobx-react-lite/badge.svg)](https://coveralls.io/github/mobxjs/mobx-react-lite)
|
5 | [![NPM downloads](https://img.shields.io/npm/dm/mobx-react-lite.svg?style=flat)](https://npmjs.com/package/mobx-react-lite)[![Minzipped size](https://img.shields.io/bundlephobia/minzip/mobx-react-lite.svg)](https://bundlephobia.com/result?p=mobx-react-lite)
|
6 | [![Discuss on Github](https://img.shields.io/badge/discuss%20on-GitHub-orange)](https://github.com/mobxjs/mobx/discussions)
|
7 | [![View changelog](https://img.shields.io/badge/changelogs.xyz-Explore%20Changelog-brightgreen)](https://changelogs.xyz/mobx-react-lite)
|
8 |
|
9 | This is a lighter version of [mobx-react](https://github.com/mobxjs/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.
|
10 | Unlike `mobx-react`, it doesn't `Provider`/`inject`, as `useContext` can be used instead.
|
11 |
|
12 | ## Compatibility table (major versions)
|
13 |
|
14 | | mobx | mobx-react-lite | Browser |
|
15 | | ---- | --------------- | ---------------------------------------------- |
|
16 | | 6 | 3 | Modern browsers (IE 11+ in compatibility mode) |
|
17 | | 5 | 2 | Modern browsers |
|
18 | | 4 | 2 | IE 11+, RN w/o Proxy support |
|
19 |
|
20 | `mobx-react-lite` requires React 16.8 or higher.
|
21 |
|
22 | ## User Guide 👉 https://mobx.js.org/react-integration.html
|
23 |
|
24 | ---
|
25 |
|
26 | ## API reference âš’
|
27 |
|
28 | ### **`observer<P>(baseComponent: FunctionComponent<P>): FunctionComponent<P>`**
|
29 |
|
30 | 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.
|
31 | Can only be used for function components. For class component support see the `mobx-react` package.
|
32 |
|
33 | ### **`<Observer>{renderFn}</Observer>`**
|
34 |
|
35 | Is a React component, which applies observer to an anonymous region in your component. `<Observer>` can be used both inside class and function components.
|
36 |
|
37 | ### **`useLocalObservable<T>(initializer: () => T, annotations?: AnnotationsMap<T>): T`**
|
38 |
|
39 | Creates an observable object with the given properties, methods and computed values.
|
40 |
|
41 | 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`).
|
42 |
|
43 | `useLocalObservable` is a short-hand for:
|
44 |
|
45 | `const [state] = useState(() => observable(initializer(), annotations, { autoBind: true }))`
|
46 |
|
47 | ### **`enableStaticRendering(enable: true)`**
|
48 |
|
49 | 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.
|
50 |
|
51 | ---
|
52 |
|
53 | ## Deprecated APIs
|
54 |
|
55 | ### **`useObserver<T>(fn: () => T, baseComponentName = "observed", options?: IUseObserverOptions): T`** (deprecated)
|
56 |
|
57 | _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_
|
58 |
|
59 | ```ts
|
60 | interface IUseObserverOptions {
|
61 | // optional custom hook that should make a component re-render (or not) upon changes
|
62 | // Supported in 2.x only
|
63 | useForceUpdate: () => () => void
|
64 | }
|
65 | ```
|
66 |
|
67 | 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).
|
68 |
|
69 | ### **`useLocalStore<T, S>(initializer: () => T, source?: S): T`** (deprecated)
|
70 |
|
71 | _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_
|
72 |
|
73 | 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.
|
74 |
|
75 | The annotations are similar to the annotations that are passed in to MobX's [`observable`](https://mobx.js.org/observable.html#available-annotations) API, and can be used to override the automatic member inference of specific fields.
|
76 |
|
77 | ### **`useAsObservableSource<T>(source: T): T`** (deprecated)
|
78 |
|
79 | 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).
|
80 |
|
81 | _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:_
|
82 |
|
83 | ```javascript
|
84 | // Before:
|
85 | function Measurement({ unit }) {
|
86 | const observableProps = useAsObservableSource({ unit })
|
87 | const state = useLocalStore(() => ({
|
88 | length: 0,
|
89 | get lengthWithUnit() {
|
90 | // lengthWithUnit can only depend on observables, hence the above conversion with `useAsObservableSource`
|
91 | return observableProps.unit === "inch"
|
92 | ? `${this.length / 2.54} inch`
|
93 | : `${this.length} cm`
|
94 | }
|
95 | }))
|
96 |
|
97 | return <h1>{state.lengthWithUnit}</h1>
|
98 | }
|
99 |
|
100 | // After:
|
101 | function Measurement({ unit }) {
|
102 | const state = useLocalObservable(() => ({
|
103 | unit, // the initial unit
|
104 | length: 0,
|
105 | get lengthWithUnit() {
|
106 | // lengthWithUnit can only depend on observables, hence the above conversion with `useAsObservableSource`
|
107 | return this.unit === "inch" ? `${this.length / 2.54} inch` : `${this.length} cm`
|
108 | }
|
109 | }))
|
110 |
|
111 | useEffect(() => {
|
112 | // sync the unit from 'props' into the observable 'state'
|
113 | state.unit = unit
|
114 | }, [unit])
|
115 |
|
116 | return <h1>{state.lengthWithUnit}</h1>
|
117 | }
|
118 | ```
|
119 |
|
120 | Note that, at your own risk, it is also possible to not use `useEffect`, but do `state.unit = unit` instead in the rendering.
|
121 | This is closer to the old behavior, but React will warn correctly about this if this would affect the rendering of other components.
|
122 |
|
123 | ## Observer batching (deprecated)
|
124 |
|
125 | _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_
|
126 |
|
127 | [Check out the elaborate explanation](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).
|
128 |
|
129 | 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.
|
130 |
|
131 | Import one of these before any React rendering is happening, typically `index.js/ts`. For Jest tests you can utilize [setupFilesAfterEnv](https://jestjs.io/docs/en/configuration#setupfilesafterenv-array).
|
132 |
|
133 | **React DOM:**
|
134 |
|
135 | > import 'mobx-react-lite/batchingForReactDom'
|
136 |
|
137 | **React Native:**
|
138 |
|
139 | > import 'mobx-react-lite/batchingForReactNative'
|
140 |
|
141 | ### Opt-out
|
142 |
|
143 | To opt-out from batching in some specific cases, simply import the following to silence the warning.
|
144 |
|
145 | > import 'mobx-react-lite/batchingOptOut'
|
146 |
|
147 | ### Custom batched updates
|
148 |
|
149 | 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.
|
150 |
|
151 | ```js
|
152 | import { observerBatching } from "mobx-react-lite"
|
153 | observerBatching(customBatchedUpdates)
|
154 | ```
|
155 |
|
156 | ## Testing
|
157 |
|
158 | Running the full test suite now requires node 14+
|
159 | But the library itself does not have this limitation
|
160 |
|
161 | In order to avoid memory leaks due to aborted renders from React
|
162 | fiber handling or React `StrictMode`, on environments that does not support [FinalizationRegistry](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry), this library needs to
|
163 | run timers to tidy up the remains of the aborted renders.
|
164 |
|
165 | This can cause issues with test frameworks such as Jest
|
166 | which require that timers be cleaned up before the tests
|
167 | can exit.
|
168 |
|
169 | ### **`clearTimers()`**
|
170 |
|
171 | Call `clearTimers()` in the `afterEach` of your tests to ensure
|
172 | that `mobx-react-lite` cleans up immediately and allows tests
|
173 | to exit.
|