DEV Community

Relay: the GraphQL client that wants to do the dirty work for you

Gabriel Nordeborn on April 16, 2020

This series of articles is written by Gabriel Nordeborn and Sean Grove. Gabriel is a frontend developer and partner at the Swedish IT consultancy ...
Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
zth profile image
Gabriel Nordeborn

Thank you Nikolai! Yes for sure, that will change how we build UI for the better. I've experimented quite a lot with the new APIs, and it's pretty amazing the control it gives you over your UI. Looking forward to the continuation of this!

Collapse
 
daniel15 profile image
Daniel Lo Nigro

This is such a great writeup! I've seen other articles where people complain about Relay being too opinionated, but you really understand why it's built the way it is. Fantastic work.

In my team at Facebook, we just started using Relay a year or two ago, and I don't think we could ever go back to the "old way" we used to do things. Relay is so good.

Collapse
 
rosavage profile image
Ro Savage

Great article, thanks Gabriel. Love these in-depth posts!

One thing I've never understood about relay is how to have a fragment request data that the fragment above it doesn't know about.

In your example, imagine the fragment that contains the tags. It would look something like

      const blogPostTags = useFragment<BlogPostHeader_blogTags>(
        graphql`
          fragment BlogPostTags_blogPost on BlogPost {
            tags  {
                 slug
                 shortName
             }
          }
        `,
        blogPost
      );

Now, imagine from this component we also wanted to be able to change add a new tag. So now we need not just the tags that the blog has, but all available tags.

If weren't using Fragments we could write a top level query that might look like

blog {
   tags { 
     slug
     shortName
   }
   blogPostById(id: $blogPostId) {
     tags {
       slug
       shortName
     }
   }
}

However, because we are using relay fragments the only way would be to pass down account from our top level query. But the BlogPost and BlogHeader don't require account. So we end up just passing account through two components that have no idea why they require account.

Now you can take this futher, maybe you have a <TagPicker /> component that can be re-used everywhere. It only requests tags { slug, shortName } but can be dozens of components down from the top level query where Blog {} is originally asked and where the fragment needs to be destructured.

Is there a nice way Relay can solve this?

Three solutions I've used is
1) Have the <TagPicker /> have query the graphql endpoint directly. But then I have unnecessary extra requests and repeated requests for the exact same data.
2) Have the <TagPicker /> use context to have the relay $key passed down without prop-drilling. However this causes race conditions when relay receives new data, and expects that the component will have it but because context hasn't re-rendered yet it's actually empty.
3) Prop-drilling down a dozen components, which makes refactoring very hard.

Collapse
 
julioxavierr profile image
Julio Xavier

Great job guys! Really well written!

Collapse
 
zth profile image
Gabriel Nordeborn

Thank you very much Júlio!

Collapse
 
beingbook profile image
Han BaHwan

the link dev.to/zth/connection-based-pagina... looks broken. is there any alternative post you recommend?

Collapse
 
zth profile image
Gabriel Nordeborn

Hi! Sorry about the links, they should point to the right place now. Here's the real one: dev.to/zth/connection-based-pagina...

Thanks for reading!

Collapse
 
beingbook profile image
Han BaHwan

official document itself might be good resource perhaps?

Collapse
 
zth profile image
Gabriel Nordeborn

Oh yes, for sure, the official docs are a great resource!

Collapse
 
stevndegwa profile image
Stephen N.

Thank you so much, Gabriel. This article gave me a great understanding of relay. Now it'll be easier to understand the docs.