David Casillas
David Casillas

Reputation: 1921

Using react.useEffect and mobx.autorun together

In the MobX with React docs, in the Side effects and observables section there is a receipe to respond to changes inside a useEffect hook.

import React from 'react'
import { autorun } from 'mobx'

function useDocumentTitle(store: TStore) {
  React.useEffect(
    () =>
      autorun(() => {
        document.title = `${store.title} - ${store.sectionName}`
      }),
    [], // note empty dependencies
  )
}

The example combines React.useEffect with mobx.autorun (but it could be mobx.reaction), but I can not see the benefit of autorun in the code. Once we are inside useEffect we can track our dependencies in the dependency array. The code is more clear, there is no need to dispose() and useEffect has a clear dependency array with what is needed.

import React from 'react'
import { autorun } from 'mobx'

function useDocumentTitle(store: TStore) {
  React.useEffect(() => document.title = `${store.title} - ${store.sectionName}`
  ,[store.title, store.sectionName])
}

Is there any reason to follow the example as given?

Here is a Code Sandbox

Upvotes: 8

Views: 9039

Answers (1)

Petr Bela
Petr Bela

Reputation: 8751

autorun creates an observer, which means it will watch for any changes in store.title and store.sectionName, and automatically run whenever they change.

Setting it up in useEffect ensures that the autorun observer is only created once, and removed when the component is unmounted. Note that useEffect doesn't actually run when the store value changes; its effect is that autorun is (un)registered when the component (un)mounts.

Your second example without autorun would still run the effect and thus update the title if this component is re-rendered by other means, either because a parent component triggers a re-render, or if this component is wrapped in an observer, as in the Sandbox example:

function Test(props) {
  // 2. rerendered by observer when the value changes

  useEffect(() => {
    // <-- 3. execute effect because (2) rendered with a different dependency
  }, [props.store.size]); // <-- 1. observer notes this value is accessed

  return ( ... );
}

// <-- 1. observe any store value that is accessed in the Test function
export default observer(Test);

(edited for clarification)

Upvotes: 6

Related Questions