Graceful GraphQL with React Hooks and MobX

February 18, 2019 0 Comments

Graceful GraphQL with React Hooks and MobX

 

 

GraphQL is definitely getting more and more attention and it’s well deserved. Raise your hand if you tried it and want to go back to fetching data from multiple endpoints. Nah, don’t worry, I think I know the answer 😎.

Apollo is the most common solution when it comes to GraphQL and I even dare to say that without them we wouldn’t be as far along as we are in GraphQL development. The community and technology they have built deserves 👏.

When React Hooks came into the light, it was only a matter of days before the unofficial project react-apollo-hooks was published. I’ve immediately jumped on the wagon and have been enjoying it since then.

Just for fun compare these three approaches for executing mutations.

Ok, you had your fun, now let’s move on. The article is about something totally different … queries. Oh, and I’ve promised some MobX, haven’t I?

Photo by AK¥N Cakiner on Unsplash

Running queries is essential to GraphQL. What would you do without your precious data? I am going to focus on the Hooks approach only since there are better resources describing the other two.

Nothing spectacular yet. Some people might object that data fetching shouldn’t be done inside the UI component. Sure, feel free to separate it if you like. Let’s focus on more pressing issues of the article.

There is a variable coming through props and passed to the query. When the value changes, a query gets re-executed. That’s cool so far and definitely beats usingcomponentDidMount to execute fetch and subsequent shenanigans when you need to update it😜.

Now imagine that the variable tag is not easily reachable. Perhaps it’s in some settings panel that’s not related to displaying the actual image. You most likely don’t want to be passing that up and down through like 10 or more layers, right? (That’s called prop drilling just for your reference.)

Wait, but this is supposed to be about MobX. Why don’t you…? Hold your horses, I will get there.

Let’s call the Context for the help here.

The SettingsProvider would be placed at some top-level to cover all components that might need it. Everything looks great and our RandomGiphy component will be re-rendered when we update settings.

Ouch! Did you just realize the same thing? Nothing?

Do you know what also happens when we update the settings? Every other component all the way down from SettingsProvider will be re-rendered! I will give you a moment to think about it…

Ok sure, in this silly example it won’t matter a bit. In a real application though, there might be some performance implications for sure.

Finally, it’s time to employ my beloved MobX to save the day!

For the SettingsProvider it makes sense to have some persistence, but I’ve left it out for brevity. Even if it were here, it wouldn't be re-rendered anytime soon, unless there is some other culprit even higher in the tree of course.

Also, notice that I haven’t separated the data and the state updater. The observable state can be mutated directly. Sure, it’s not always the brightest idea, and I encourage you to create actions for some level of abstraction if you like. Or just have a look at the brilliant mobx-state-tree.

The RandomGiphy is pretty much the same except it got wrapped into the observer HOC from the MobX family. It will take care of re-rendering the component (and nothing else) when tag is updated 😍

Ok, we are done here. Have a nice day and see you again soon…

No, wait! We can do even better. We have the ability to make custom hooks. Why don’t we separate querying logic into one?

Once again, this is a fairly silly example, but such separation of concerns can surely be useful. Notice that we don’t need observer for our component anymore because that logic happens inside the hook, although it’s not as nice and declarative. Besides, such separation could prove useful for integration testing too 🤓.

And what about loading & error states?

The errors are somewhat simple. You can let it bubble up in a tree by throwing it and catching with error boundaries. You might want to send it to some reporting service or perhaps show an error toast? Or if this doesn’t fit your needs, just return an error from the hook and handle it in the component with some UI.

Loading is mostly just temporary for now. It’s fairly safe to assume that if nullis returned from the hook, it means that data is still loading and that the UI should probably display a spinner. Later on, when React Suspense for data fetching gets some love, I am sure there will be some other ways we can only dream of ❤️.

I’ve prepared a fully working demo for you to see everything in action. It’s not some fancy app (I am not a designer), but for a showcase, it will do. There are some small additions to it not mentioned here. Feel free to experiment with it.

Warning: At this moment it seems there is some sort of bug. In some cases, when changing the input value, data gets fetched but the component is not re-rendered. See the issue for more details. One workaround is to keep using an observer HOC for the component, but I hope to find solution to this.


Tag cloud