Research
Security News
Malicious PyPI Package ‘pycord-self’ Targets Discord Developers with Token Theft and Backdoor Exploit
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
mobx-react-lite
Advanced tools
Lightweight React bindings for MobX based on React 16.8+ and Hooks
mobx-react-lite is a lightweight wrapper around MobX that provides React bindings for functional components. It allows you to use MobX for state management in your React applications with minimal boilerplate and high performance.
Observer Component
The `observer` function is used to create a reactive component that will automatically re-render when the observed state changes. In this example, the `Counter` component re-renders whenever `counter.count` is updated.
import React from 'react';
import { observer } from 'mobx-react-lite';
import { observable } from 'mobx';
const counter = observable({ count: 0 });
const Counter = observer(() => (
<div>
<button onClick={() => counter.count++}>Increment</button>
<p>{counter.count}</p>
</div>
));
export default Counter;
Using MobX stores
This example demonstrates how to use MobX stores with `mobx-react-lite`. The `CounterStore` class is an observable store, and the `Counter` component observes changes to the store and re-renders accordingly.
import React from 'react';
import { observer } from 'mobx-react-lite';
import { observable } from 'mobx';
class CounterStore {
@observable count = 0;
increment() {
this.count++;
}
}
const counterStore = new CounterStore();
const Counter = observer(() => (
<div>
<button onClick={() => counterStore.increment()}>Increment</button>
<p>{counterStore.count}</p>
</div>
));
export default Counter;
Using hooks with MobX
The `useLocalObservable` hook allows you to create local observable state within a functional component. This example shows how to use the hook to create a local counter state and update it within the component.
import React from 'react';
import { observer, useLocalObservable } from 'mobx-react-lite';
const Counter = observer(() => {
const counter = useLocalObservable(() => ({ count: 0, increment() { this.count++; } }));
return (
<div>
<button onClick={counter.increment}>Increment</button>
<p>{counter.count}</p>
</div>
);
});
export default Counter;
Redux is a popular state management library for JavaScript applications. Unlike MobX, which uses observables and reactive programming, Redux relies on a unidirectional data flow and immutable state updates. Redux is often used with React through the `react-redux` bindings.
Recoil is a state management library for React that provides a set of utilities for managing state in a more granular and efficient way. It uses atoms and selectors to manage state and derive computed values. Recoil is designed to work seamlessly with React's concurrent mode.
Zustand is a small, fast, and scalable state management library for React. It uses hooks to manage state and provides a simple API for creating and updating state. Zustand is less opinionated than MobX and can be a good choice for simpler state management needs.
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.
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.
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.
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.
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'
To opt-out from batching in some specific cases, simply import the following to silence the warning.
import 'mobx-react-lite/batchingOptOut'
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)
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.
FAQs
Lightweight React bindings for MobX based on React 16.8+ and Hooks
We found that mobx-react-lite demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.
Security News
Snyk's use of malicious npm packages for research raises ethical concerns, highlighting risks in public deployment, data exfiltration, and unauthorized testing.