Making an application responsive using Mobx requires only three simple steps. In the second step: Creating a view to respond to changes in state, the @Observer decorator is used to convert the React component into a responsive component. In addition to @Observer, there are three other ways to add responsiveness to React components.

There are four ways to add responsiveness:

  • @observer
  • observer HOC
  • Observer component
  • userObserver hook

@ the observer a decorator

The Observer function/decorator can be used to transform the React component into a responsive component. It wraps the component’s render function in mobx.autorun to ensure that any component can force a refresh of the component if the data used in the rendering changes. The Observer is provided by a separate Mox-React package.

import { observer } from "mobx-react";

var timerData = observable({
    secondsPassed: 0
});

setInterval(() => {
    timerData.secondsPassed++;
}, 1000);

@observer class Timer extends React.Component {
    render() {
        return (<span>Seconds passed: { this.props.timerData.secondsPassed } </span> )
    }
};

ReactDOM.render(<Timer timerData={timerData} />, document.body);
Copy the code

observer HOC

The Observer converts a component into a responsive component. Observers are available in mobx-React and Mobx-React-Lite, but the latter observer does not support converting a class component into a responsive component.

observer<P>(baseComponent: React.FC<P>, options? : IObserverOptions): React.FC<P> interface IObserverOptions { // Pass true to use React.forwardRef over the inner component. It's false by the default. forwardRef? : boolean }Copy the code

The Observer in Mobx-React supports converting functional components and class components into responsive components. If the component is functional, the options parameter can be used in the Observer, but not in the class component.

Transform functional components into reactive components

import { observer, useLocalStore } from 'mobx-react' // 6.x or [email protected]

export const Counter = observer<Props>(props => {
  const store = useLocalStore(() => ({
    count: props.initialCount,
    inc() {
      store.count += 1
    },
  }))

  return (
    <div>
      <span>{store.count}</span>
      <button onClick={store.inc}>Increment</button>
    </div>
  )
})
Copy the code

The Observer converts a component into a responsive component that automatically keeps track of which observable is used and automatically rerenders the component when the value changes.

Transform a class component into a responsive component

import { observer } from "mobx-react" const TodoView = observer( class TodoView extends React.Component<IProps, IState> { store = useLocalStore(() => ({ count: props.initialCount, inc() { store.count += 1 }, })) render() { return <div> <span>{this.store.count}</span> <button onClick={this.store.inc}>Increment</button> </div> } })Copy the code

The Observer uses the React.memo internally, so we don’t need to encapsulate the memo ourselves. However, it’s worth noting that the memo encapsulated in the Observer is only a shallow comparison by default, because Mobx-React says, The Observed component rarely needs to be updated and rendered based on complex props.

Observer component

<Observer>{ renderFn }</Observer>
Copy the code

The Observer Component accepts a function with no arguments as children, and that function must return the React element.

import { Observer, useLocalStore } from 'mobx-react';

export function ObservePerson() {
  
  const person = useLocalStore(() => ({ name: 'John' }));
  
  return (
    <div>
      {person.name} <i>I will never change my name</i>
      <div>
        <Observer>{() => <div>{person.name}</div>}</Observer>
        <button onClick={() => (person.name = 'Mike')}>
          I want to be Mike
        </button>
      </div>
    </div>
  )
}
Copy the code

Note that the Observer Component can only make renderFn return components that are responsive. If renderFn returns nested components, those components must become responsive on their own.

Take a look at the following example:

Import {Observer} from 'mobx-react' // 6.x or [email protected] function ObservePerson() {return (<Observer> {())  => ( <GetStore>{store => <div className="self">{store.wontSeeChangesToThis}</div>}</GetStore> )} </Observer> ) }Copy the code

In the example above, renderFn returns a nested component; div className self is not responsive. If you want to become responsive, you need to wrap it again with an Observer:

Import {Observer} from 'mox-react' // 6.x or [email protected] function ObservePerson() {return (<GetStore>) {store => ( <Observer>{() => <div>{store.changesAreSeenAgain}</div>}</Observer> )} </GetStore> ) }Copy the code

We can also use render props instead of children to make the component responsive, as in the following example:

import { Observer, useLocalStore } from 'mobx-react';

export function ObservePerson() {
  
  const person = useLocalStore(() => ({ name: 'John' }));
  
  return (
    <div>
      {person.name} <i>I will never change my name</i>
      <div>
    
        <Observer render={() => <div>{person.name}</div>} />
    
        <button onClick={() => (person.name = 'Mike')}>
          I want to be Mike
        </button>
      </div>
    </div>
  )
}
Copy the code

In the above example, the components that need to be converted to responsiveness are placed in the Render props of the Observer component.

useObserver hook

useObserver<T>(fn: () => T, baseComponentName = "observed", options? : IUseObserverOptions): T interface IUseObserverOptions { // optional custom hook that should make a component re-render (or not) upon changes useForceUpdate: () => () => void }Copy the code

This custom Hook method can also make components responsive:

import { useObserver, } from 'mobx-react' // 6.x or [email protected] function Person() {const Person = useLocalStore(() =>  ({ name: 'John' })) return useObserver(() => ( <div> {person.name} <button onClick={() => (person.name = 'Mike')}>No! I am Mike</button> </div> )) }Copy the code

One advantage of this Hook method is that any Hook changes observable, the component does not render repeatedly. One disadvantage is that even if you use it in one part of the component, it can cause all updates to the component. So be careful with this hook method.

This custom hook method exists in the Mobx-React-Lite library, or mobx-react@6. Note that this hook method has been deprecated in mobx-React-Lite 3.x.

Reference Documents:

mobx-react.js.org/observe-how

Github.com/mobxjs/mobx…

Github.com/mobxjs/mobx…