Security News
PyPI’s New Archival Feature Closes a Major Security Gap
PyPI now allows maintainers to archive projects, improving security and helping users make informed decisions about their dependencies.
mobx-react-lite
Advanced tools
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 next iteration of mobx-react coming from introducing React hooks which simplifies a lot of internal workings of this package.
You need React version 16.8.0 and above
Class based components are not supported except using <Observer>
directly in class render
method. If you want to transition existing projects from classes to hooks (as most of us do), you can use this package alongside the mobx-react just fine. The only conflict point is about the observer
HOC. Subscribe to this issue for a proper migration guide.
Project is written in TypeScript and provides type safety out of the box. No Flow Type support is planned at this moment, but feel free to contribute.
The site contains various examples and recipes for using MobX in React world. Feel free to contribute. The API reference of this package follows 👇.
<Observer>{renderFn}</Observer>
(user guide)
observer<P>(baseComponent: FunctionComponent<P>, options?: IObserverOptions): FunctionComponent<P>
(user guide)
interface IObserverOptions {
// Pass true to use React.forwardRef over the inner component. It's false by the default.
forwardRef?: boolean
}
useObserver<T>(fn: () => T, baseComponentName = "observed", options?: IUseObserverOptions): T
(user guide)
interface IUseObserverOptions {
// optional custom hook that should make a component re-render (or not) upon changes
useForceUpdate: () => () => void
}
useLocalStore<T, S>(initializer: () => T, source?: S): T
(user guide)
useAsObservableSource<T>(source: T): T
(user guide)
Feel free to try out mobx-react-lite@next
which is based on latest 1.x, but contains experimental support for handling Concurrent mode in React properly.
Following utilities are still available in the package, but they are deprecated and will be removed in the next major version (2.x). As such, they are not mentioned in the user guide and it's not recommend to continue using these.
useObservable<T>(initialValue: T): T
Use the
useLocalStore
instead (user guide)
React hook that allows creating observable object within a component body and keeps track of it over renders. Gets all the benefits from observable objects including computed properties and methods. You can also use arrays, Map and Set.
Warning: With current implementation you also need to wrap your component to observer
. It's also possible to have useObserver
only in case you are not expecting rerender of the whole component.
import { observer, useObservable, useObserver } from "mobx-react-lite"
const TodoList = () => {
const todos = useObservable(new Map<string, boolean>())
const todoRef = React.useRef()
const addTodo = React.useCallback(() => {
todos.set(todoRef.current.value, false)
todoRef.current.value = ""
}, [])
const toggleTodo = React.useCallback((todo: string) => {
todos.set(todo, !todos.get(todo))
}, [])
return useObserver(() => (
<div>
{Array.from(todos).map(([todo, done]) => (
<div onClick={() => toggleTodo(todo)} key={todo}>
{todo}
{done ? " ✔" : " ⏲"}
</div>
))}
<input ref={todoRef} />
<button onClick={addTodo}>Add todo</button>
</div>
))
}
Lazy initialization (similar to React.useState
) is not available. In most cases your observable state should be a plain object which is cheap to create. With useObserver
the component won't even rerender and state won't be recreated. In case you really want a more complex state or you need to use observer
, it's very simple to use MobX directly.
import { observer } from "mobx-react-lite"
import { observable } from "mobx"
import { useState } from "react"
const WithComplexState = observer(() => {
const [complexState] = useState(() => observable(new HeavyState()))
if (complexState.loading) {
return <Loading />
}
return <div>{complexState.heavyName}</div>
})
Note that if you want to track a single scalar value (string, number, boolean), you would need a boxed value which is not recognized by useObservable
. However, we recommend to just useState
instead which gives you almost same result (with slightly different API).
useComputed(func: () => T, inputs: ReadonlyArray<any> = []): T
Use the
useLocalStore
instead (user guide)
Another React hook that simplifies computational logic. It's just a tiny wrapper around MobX computed function that runs computation whenever observable values change. In conjuction with observer
the component will rerender based on such a change.
const Calculator = observer(({ hasExploded }: { hasExploded: boolean }) => {
const inputRef = React.useRef()
const inputs = useObservable([1, 3, 5])
const result = useComputed(
() => (hasExploded ? "💣" : inputs.reduce(multiply, 1) * Number(!hasExploded)),
[hasExploded]
)
return (
<div>
<input ref={inputRef} />
<button onClick={() => inputs.push(parseInt(inputRef.current.value) | 1)}>
Multiply
</button>
<div>
{inputs.join(" * ")} = {result}
</div>
</div>
)
})
Notice that since the computation depends on non-observable value, it has to be passed as a second argument to useComputed
. There is React useMemo
behind the scenes and all rules applies here as well except you don't need to specify dependency on observable values.
useDisposable<D extends TDisposable>(disposerGenerator: () => D, inputs: ReadonlyArray<any> = []): D
Use the
React.useEffect
instead (user guide)
The disposable is any kind of function that returns another function to be called on a component unmount to clean up used resources. Use MobX related functions like reaction
, autorun
, when
, observe
, or anything else that returns a disposer.
Returns the generated disposer for early disposal.
Example (TypeScript):
import { reaction } from "mobx"
import { observer, useComputed, useDisposable } from "mobx-react-lite"
const Name = observer((props: { firstName: string; lastName: string }) => {
const fullName = useComputed(() => `${props.firstName} ${props.lastName}`, [
props.firstName,
props.lastName
])
// when the name changes then send this info to the server
useDisposable(() =>
reaction(
() => fullName,
() => {
// send this to some server
}
)
)
// render phase
return `Your full name is ${props.firstName} ${props.lastName}`
})
FAQs
Lightweight React bindings for MobX based on React 16.8+ and Hooks
The npm package mobx-react-lite receives a total of 1,110,961 weekly downloads. As such, mobx-react-lite popularity was classified as popular.
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.
Security News
PyPI now allows maintainers to archive projects, improving security and helping users make informed decisions about their dependencies.
Research
Security News
Malicious npm package postcss-optimizer delivers BeaverTail malware, targeting developer systems; similarities to past campaigns suggest a North Korean connection.
Security News
CISA's KEV data is now on GitHub, offering easier access, API integration, commit history tracking, and automated updates for security teams and researchers.