Skip to content

Instantly share code, notes, and snippets.

@jamonholmgren
Last active April 20, 2023 21:59
Show Gist options
  • Save jamonholmgren/2b5b40c199e4046010cc8528f785cc44 to your computer and use it in GitHub Desktop.
Save jamonholmgren/2b5b40c199e4046010cc8528f785cc44 to your computer and use it in GitHub Desktop.

Q. Under what conditions is MobX-state-tree optimized to memoize/prevent accidental re-renders that Immutable libraries that create copies like Redux/RTK are more prone to?

MST (and really it’s MobX under the hood doing this) doesn’t even really diff at all; instead, it observes changes to objects via JS proxies. It also tracks what properties are accessed on observed objects via JS proxies.

So, let’s say you have an object like this, that is an observed MobX object (we’ll ignore MST, since it’s the same for both):

const user = makeAutoObservable({
  name: "Jamon",
  age: 41,
  photoURL: "https://example.com/jamon.jpg"
})

And then elsewhere you’re observing, using mobx-react-lite, that object, in a React component:

const Avatar = observer(() => {
  return <Image source={{ uri: user.photoURL }} />
})

… MobX will note that the user object had its photoURL accessed.

Then, if that ever changes, it’ll tell that component to rerender.

runInAction(() => {
  user.photoURL = "https://example.com/newavatars/jamon.png"
})

This works also for observable arrays, with some caveats.

The primary benefit is that the accessed properties are observed automatically. With Redux/RTK, you have to ensure you’re doing your selectors correctly or you'll have problems.

Basically ... either do your selectors by hand (Redux/RTK), or have observables do it for you (MobX/MST).

Some other things you have to watch for:

  1. Shallow equality checks: Redux's connect function and useSelector hook from react-redux rely on shallow equality checks. If new objects or arrays are created in mapStateToProps, useSelector, or reducer, it can cause unnecessary re-renders, as the reference will be different even if the data is the same. MobX/MST do not have this issue as they're not doing equality checks but rather observing for updates.
  2. Overly broad subscriptions: When a component subscribes to a large portion of the state, it will re-render whenever that portion changes, even if the component doesn't use all of the data. This is an antipattern in Redux but it's easy to slip into if you're not careful. MobX/MST don't have this issue as they only observe what is actually used.
  3. Not using memoization: If you have expensive calculations or component rendering based on state, you should be using useMemo from React or something like createSelector from Reselect to memoize the results. MobX/MST automatically memoize components that are observed using observer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment