In MobX, observer is a Higher-Order Component (HOC) used to convert React components into reactive components. When the data used by a component changes, the component automatically re-renders.
Basic Usage of observer
1. Using observer with Class Components
javascriptimport React from 'react'; import { observer } from 'mobx-react'; import { observable } from 'mobx'; class Store { @observable count = 0; } const store = new Store(); @observer class Counter extends React.Component { render() { return ( <div> <p>Count: {store.count}</p> <button onClick={() => store.count++}>Increment</button> </div> ); } }
2. Using observer with Functional Components
javascriptimport React from 'react'; import { observer } from 'mobx-react-lite'; import { observable } from 'mobx'; class Store { @observable count = 0; } const store = new Store(); const Counter = observer(() => { return ( <div> <p>Count: {store.count}</p> <button onClick={() => store.count++}>Increment</button> </div> ); });
How observer Works
1. When Component Mounts
- MobX creates a reaction to track all observables accessed in the component's render function
- Establishes dependency relationships between the component and observables
2. When State Changes
- When an observable is modified, MobX detects the dependency change
- Marks the component as needing re-render
- In the next event loop, triggers the component's re-render
3. When Component Unmounts
- Automatically cleans up reactions and dependency relationships
- Avoids memory leaks
observer's Optimization Features
1. Fine-grained Updates
observer only re-renders components that truly need updating:
javascript@observer class Parent extends React.Component { render() { return ( <div> <ChildA /> <ChildB /> </div> ); } } @observer class ChildA extends React.Component { render() { // Only depends on store.count return <div>Count: {store.count}</div>; } } @observer class ChildB extends React.Component { render() { // Only depends on store.name return <div>Name: {store.name}</div>; } }
When store.count changes, only ChildA will re-render, not ChildB.
2. shouldComponentUpdate Optimization
observer automatically implements shouldComponentUpdate to avoid unnecessary renders:
- Only re-renders when observables the component depends on actually change
- Even if the parent component re-renders, child components may not re-render
3. Batched Updates
Multiple state changes are batched and trigger only one re-render:
javascriptrunInAction(() => { store.count++; store.name = 'New Name'; });
Best Practices for observer
1. Only Use observer Where Needed
Not all components need observer, only use it on components that need to respond to state changes:
javascript// Doesn't need observer const Header = () => <h1>My App</h1>; // Needs observer const Counter = observer(() => { return <div>Count: {store.count}</div>; });
2. Avoid Creating New Objects in render
Creating new objects in render causes unnecessary re-renders:
javascript// Bad practice const BadComponent = observer(() => { const style = { color: 'red' }; // Creates new object every render return <div style={style}>{store.count}</div>; }); // Good practice const style = { color: 'red' }; // Define outside component const GoodComponent = observer(() => { return <div style={style}>{store.count}</div>; });
3. Use computed to Optimize Calculations
Use computed outside the component to optimize calculation logic:
javascript// Bad practice const BadComponent = observer(() => { const fullName = `${store.firstName} ${store.lastName}`; return <div>{fullName}</div>; }); // Good practice class Store { @observable firstName = 'John'; @observable lastName = 'Doe'; @computed get fullName() { return `${this.firstName} ${this.lastName}`; } } const GoodComponent = observer(() => { return <div>{store.fullName}</div>; });
4. Use React.memo with observer
For pure presentation components, you can combine with React.memo:
javascriptconst PureComponent = React.memo(observer(() => { return <div>{store.count}</div>; }));
Common Issues
1. Component Not Updating
Ensure:
- Component is wrapped with observer
- Accessing observables, not plain objects
- State modifications are done in actions
2. Over-rendering
If component over-renders, check:
- Are new objects being created in render?
- Is computed being used to optimize calculations?
- Can the component be split to reduce dependencies?
3. Memory Leaks
Ensure:
- observer automatically cleans up when component unmounts
- Manually created reactions need manual cleanup
Summary
observer is the core of MobX and React integration, achieving efficient reactive updates through fine-grained dependency tracking. Using observer correctly and following best practices can build high-performance React applications.