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:
- Fetch the data from the top-level component,
setState
with the results. - Pass fetch handlers from the top-level component to subcomponents.
- 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>
}
}
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>
}
}
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)