Tim P
Tim P

Reputation: 29

Using Mobx observables with React dependencies

Mobx docs says to use pattern useEffect(reaction(..)) to track observable changes, which looks like some cross-breeding to me. Whats the problem of using react dependencies array to achieve that? I did a basic test, and it works as intended:

const Hello = observer(() => {
  const {
    participantStore: { audioDisabled },
  } = useStores();
  useEffect(() => {
    console.log('changed', audioDisabled);
  }, [audioDisabled]);

  return <h1>TEST ME</h1>;
});

Upvotes: 1

Views: 2369

Answers (2)

Patrick Fowler
Patrick Fowler

Reputation: 176

Mixing MobX observables and hooks can be mostly painless, but there are a few things to look out for. The most common thing to watch out for is that adding observable values to the dependencies array will not always trigger the effect. Under the surface, MobX objects and arrays are stable references to proxy objects. So even though the value of the observable changes, the useEffect hook doesn't always pick up on that change.

The solution is simple, and is outlined in the MobX Docs under React Integration: useEffect and observables:

Using useEffect requires specifying dependencies. With MobX that isn't really needed, since MobX has already a way to automatically determine the dependencies of an effect, autorun. Combining autorun and coupling it to the life-cycle of the component using useEffect is luckily straightforward

In practice, this looks like:

const Hello = observer(() => {
  const { participantStore } = useStores();
  useEffect(() => autorun(() => {
    console.log('changed', participantStore.audioDisabled);
  }), []);

  return <h1>Audio is {!participantStore.audioDisabled && 'NOT '}Disabled</h1>;
});

There are a few things to be mindful of:

  1. If you are also dealing with local state (via a useState or other hook), you will need to include those in the dependencies array.
  2. Be sure to return the autorun function from your useEffect hook. This ensures that the listener is de-registered on component unmount.
  3. Your linter will likely get frustrated with missing dependencies. I won't make a recommendation either way since there are pros and cons to either disabling it globally, or keeping it enabled and disabling it per-line. It largely depends on how much local state you will be dealing with.

Upvotes: 0

Danila
Danila

Reputation: 18506

There is absolutely no problem with using React things like useEffect, useMemo and etc with MobX. You just need to list all dependencies and if there are many of them maybe it is easier to use reaction or autorun.

So feel free to use whatever way you like more.

Upvotes: 1

Related Questions