DEV Community

Cover image for Mobx walks into a package.json
Joey Mink
Joey Mink

Posted on

Mobx walks into a package.json

After a few small React apps, we decided to attack a big one. One that would obtain a lot more data from our server-side API. That data would be shared by many components. Previous experience taught us that disseminating the data to all interested components is tedious. Our approach has typically been:

  1. Fetch the data from the top-level component, setState with the results.
  2. Pass fetch handlers from the top-level component to subcomponents.
  3. Pass top-level component's fetch results to subcomponents via properties.

To oversimplify (with pseudoJS off the top of my head):

class Data {
  luckyNumber = 0;

  fetchLuckyNumber(callback){
    apiCall('/api/lucky_number', callback);
  }
}

<TopLevelComponent data={new Data()}/>

class TopLevelComponent extends React.Component {

  /* plumbing */
  fetchLuckyNumber(){
    data.fetchLuckyNumber((num) => (this.setState({ lucky_number: num }));
  }

  render() {
    return <SubComponent data={this.props.data}
             /* plumbing */
             fetchLuckyNumber={this.fetchLuckyNumber} />
  }
}

class SubComponent extends React.Component {
  render() {
    return <p>
             Lucky number: {this.props.data.luckyNumber}!
             <a onClick={this.props.fetchLuckyNumber}>Update Lucky Number</a>
           </p>
  }
}
Enter fullscreen mode Exit fullscreen mode

The takeaways from that contrived example are few. First, all data fetching for the app is initiated by TopLevelComponent. Second, dissemination of fetched data happens when TopLevelComponent sets state (which triggers a render of subcomponents). Third, subcomponents have to receive handlers from the parent to trigger the fetch and dissemination. This works, but it's verbose -- and gets worse when you have lots of nested subcomponents.

There are libraries out there to help deal with this problem, and a co-worker of mine recommended Mobx. ZOMG I'm so glad he did. Here's why:

class Data {
  @observable luckyNumber = 0;

  fetchLuckyNumber(callback){
    /* luckyNumber assignment triggers Mobx's magic */
    apiCall('/api/lucky_number', (num)=>(this.luckyNumber = num);
  }
}

<TopLevelComponent data={new Data()}/>

class TopLevelComponent extends React.Component {
  render() {
    return <SubComponent data={this.props.data} />
  }
}

@observer
class SubComponent extends React.Component {
  render() {
    /* Referencing luckyNumber automatically makes this component reactive */
    return <p>
             Lucky number: {this.props.data.luckyNumber}!
             <a onClick={this.props.data.fetchLuckyNumber}>Update Lucky Number</a>
           </p>
  }
}
Enter fullscreen mode Exit fullscreen mode

So above, SubComponent will re-render every time the value of data.luckyNumber changes. Mobx will ensure the render method of SubComponent is called, which makes the plumbing so much easier (or better said, non-existent?).

I ðŸ’‒.

Top comments (0)