Top Related Projects
The library for web and native user interfaces.
A JS library for predictable global state management
Simple, scalable state management.
A reactive programming library for JavaScript
This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
Build forms in React, without the tears 😭
Quick Overview
MobX-React-Lite is a lightweight React bindings package for MobX, a simple and scalable state management solution. It provides the essential functionalities of MobX-React with a smaller footprint, optimized for React Hooks and functional components.
Pros
- Lightweight and optimized for performance
- Seamless integration with React Hooks
- Simple and intuitive API for state management
- Automatic re-rendering of components when observed state changes
Cons
- Limited support for class components (focused on functional components)
- Smaller feature set compared to full MobX-React
- Learning curve for developers new to MobX concepts
- Potential for overuse of observables, leading to unnecessary re-renders
Code Examples
- Creating and using an observable store:
import { makeAutoObservable } from 'mobx';
import { observer } from 'mobx-react-lite';
const store = makeAutoObservable({
count: 0,
increment() {
this.count++;
}
});
const Counter = observer(() => (
<div>
Count: {store.count}
<button onClick={() => store.increment()}>Increment</button>
</div>
));
- Using
useLocalObservable
for local component state:
import { useLocalObservable } from 'mobx-react-lite';
const TodoList = observer(() => {
const todo = useLocalObservable(() => ({
items: [],
addItem(item) {
this.items.push(item);
}
}));
return (
<div>
<ul>{todo.items.map(item => <li key={item}>{item}</li>)}</ul>
<button onClick={() => todo.addItem('New Item')}>Add Item</button>
</div>
);
});
- Using
useObserver
for fine-grained reactivity:
import { useObserver } from 'mobx-react-lite';
const UserProfile = ({ user }) => {
return useObserver(() => (
<div>
<h1>{user.name}</h1>
<p>Email: {user.email}</p>
<p>Posts: {user.posts.length}</p>
</div>
));
};
Getting Started
To start using MobX-React-Lite in your project:
-
Install the package:
npm install mobx mobx-react-lite
-
Create an observable store:
import { makeAutoObservable } from 'mobx'; const store = makeAutoObservable({ // Your state and actions here });
-
Use the
observer
HOC to wrap your components:import { observer } from 'mobx-react-lite'; const MyComponent = observer(() => { // Your component logic here });
-
Start using the store in your components:
const MyComponent = observer(() => { return <div>{store.someValue}</div>; });
Competitor Comparisons
The library for web and native user interfaces.
Pros of React
- Larger ecosystem and community support
- More comprehensive documentation and learning resources
- Wider adoption in industry, leading to better job prospects
Cons of React
- Steeper learning curve for beginners
- More boilerplate code required for state management
- Frequent updates and changes can lead to compatibility issues
Code Comparison
React:
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
MobX-React-Lite:
import React from 'react';
import { observer } from 'mobx-react-lite';
import { makeAutoObservable } from 'mobx';
class CounterStore {
count = 0;
constructor() {
makeAutoObservable(this);
}
increment() {
this.count++;
}
}
const counterStore = new CounterStore();
const Counter = observer(() => (
<button onClick={() => counterStore.increment()}>{counterStore.count}</button>
));
The React example uses hooks for state management, while MobX-React-Lite utilizes observables and actions for a more centralized approach to state management. MobX-React-Lite offers a simpler syntax for complex state updates but requires additional setup compared to React's built-in state management.
A JS library for predictable global state management
Pros of Redux
- Predictable state management with a single source of truth
- Excellent debugging tools and time-travel debugging
- Large ecosystem and community support
Cons of Redux
- Steep learning curve and boilerplate code
- Can be overkill for small to medium-sized applications
- Requires careful consideration of immutability
Code Comparison
Redux:
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
default:
return state
}
}
MobX-React-Lite:
import { makeAutoObservable } from 'mobx'
class Counter {
count = 0
constructor() {
makeAutoObservable(this)
}
increment() {
this.count++
}
}
MobX-React-Lite offers a more straightforward and less verbose approach to state management compared to Redux. It uses observable state and actions, which can lead to more intuitive and less boilerplate code. However, Redux provides a more structured and predictable state management solution, which can be beneficial for larger applications or teams that require strict control over state changes.
Both libraries have their strengths and use cases. Redux excels in complex applications with intricate state management needs, while MobX-React-Lite shines in simpler scenarios where ease of use and reduced boilerplate are priorities.
Simple, scalable state management.
Pros of MobX
- More feature-rich and flexible, offering advanced state management capabilities
- Supports both React and non-React applications
- Provides decorators for easier and more concise state management
Cons of MobX
- Larger bundle size due to additional features
- Steeper learning curve for beginners
- More complex setup and configuration
Code Comparison
MobX:
import { makeAutoObservable } from "mobx";
class Store {
count = 0;
constructor() {
makeAutoObservable(this);
}
increment() {
this.count++;
}
}
MobX-React-Lite:
import { makeAutoObservable } from "mobx";
import { observer } from "mobx-react-lite";
const Store = makeAutoObservable({ count: 0, increment() { this.count++; } });
const Counter = observer(() => <button onClick={Store.increment}>Count: {Store.count}</button>);
Key Differences
- MobX-React-Lite is specifically designed for React applications using hooks
- MobX-React-Lite has a smaller bundle size and simpler API
- MobX-React-Lite focuses on functional components and hooks, while MobX supports both class and functional components
- MobX offers more advanced features like computed values and reactions, which are not available in MobX-React-Lite
Use Cases
- Choose MobX for complex state management needs or non-React applications
- Opt for MobX-React-Lite in React projects with simpler state requirements or when bundle size is a concern
A reactive programming library for JavaScript
Pros of RxJS
- More powerful and flexible for complex asynchronous operations
- Extensive set of operators for data transformation and manipulation
- Better suited for handling multiple data streams and event-based programming
Cons of RxJS
- Steeper learning curve and more complex API
- Can be overkill for simpler React applications
- Requires more boilerplate code for basic state management
Code Comparison
MobX React Lite:
import { observer } from "mobx-react-lite";
import { makeAutoObservable } from "mobx";
class Store {
count = 0;
constructor() {
makeAutoObservable(this);
}
increment() {
this.count++;
}
}
const Counter = observer(({ store }) => (
<button onClick={() => store.increment()}>{store.count}</button>
));
RxJS:
import { BehaviorSubject } from "rxjs";
import { map } from "rxjs/operators";
import { useObservable } from "rxjs-hooks";
const count$ = new BehaviorSubject(0);
const increment = () => count$.next(count$.value + 1);
const Counter = () => {
const count = useObservable(() => count$.pipe(map(x => x)));
return <button onClick={increment}>{count}</button>;
};
This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
Pros of Vue
- More comprehensive framework with built-in routing and state management
- Gentler learning curve, especially for beginners
- Flexible and adaptable to different project sizes and complexities
Cons of Vue
- Larger bundle size compared to MobX-React-Lite
- Less focused on specific React integration
- May have more overhead for simple applications
Code Comparison
Vue:
<template>
<div>{{ count }}</div>
</template>
<script>
export default {
data() {
return { count: 0 }
}
}
</script>
MobX-React-Lite:
import { observer } from 'mobx-react-lite'
import { makeAutoObservable } from 'mobx'
class Counter {
count = 0
constructor() {
makeAutoObservable(this)
}
}
const CounterView = observer(({ counter }) => <div>{counter.count}</div>)
Vue provides a more declarative approach with its template syntax, while MobX-React-Lite offers a more programmatic way to handle state and reactivity within React components. Vue's single-file component structure combines template, script, and style in one file, whereas MobX-React-Lite separates concerns more explicitly within the React ecosystem.
Build forms in React, without the tears 😭
Pros of Formik
- Specialized for form handling, offering a comprehensive solution for form state management and validation
- Reduces boilerplate code significantly for complex forms
- Integrates well with popular validation libraries like Yup
Cons of Formik
- Limited to form-specific use cases, unlike MobX which can manage global state
- Steeper learning curve for developers new to form libraries
- May introduce unnecessary complexity for simple forms
Code Comparison
Formik:
<Formik
initialValues={{ email: '', password: '' }}
onSubmit={(values) => console.log(values)}
>
{({ handleSubmit, handleChange }) => (
<form onSubmit={handleSubmit}>
<input name="email" onChange={handleChange} />
<input name="password" type="password" onChange={handleChange} />
<button type="submit">Submit</button>
</form>
)}
</Formik>
MobX React Lite:
const FormStore = observable({
email: '',
password: '',
setEmail(value) { this.email = value; },
setPassword(value) { this.password = value; },
});
const FormComponent = observer(() => (
<form onSubmit={() => console.log(FormStore)}>
<input value={FormStore.email} onChange={(e) => FormStore.setEmail(e.target.value)} />
<input type="password" value={FormStore.password} onChange={(e) => FormStore.setPassword(e.target.value)} />
<button type="submit">Submit</button>
</form>
));
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
mobx-react-lite
ð¨ð¨ð¨ This repo has been moved to mobx
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.
Top Related Projects
The library for web and native user interfaces.
A JS library for predictable global state management
Simple, scalable state management.
A reactive programming library for JavaScript
This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
Build forms in React, without the tears 😭
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot