<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Gabriel Nordeborn</title>
    <description>The latest articles on Forem by Gabriel Nordeborn (@zth).</description>
    <link>https://forem.com/zth</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F347622%2Fa24c7df7-5a14-4cb9-b9db-0f2fd96e976d.jpeg</url>
      <title>Forem: Gabriel Nordeborn</title>
      <link>https://forem.com/zth</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/zth"/>
    <language>en</language>
    <item>
      <title>Practical uses for abstract types in ReScript</title>
      <dc:creator>Gabriel Nordeborn</dc:creator>
      <pubDate>Mon, 27 Feb 2023 17:55:15 +0000</pubDate>
      <link>https://forem.com/zth/practical-uses-for-abstract-types-in-rescript-16g6</link>
      <guid>https://forem.com/zth/practical-uses-for-abstract-types-in-rescript-16g6</guid>
      <description>&lt;p&gt;Abstract types are types with no content. They look like this in ReScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just a type definition, but no content. The type is named &lt;code&gt;email&lt;/code&gt;, so we can kind of guess it's a string, but there's no way to use it like a string, because it's &lt;em&gt;opaque&lt;/em&gt; to the type system - we can't know what's inside. &lt;/p&gt;

&lt;p&gt;Looks useless at a first glance? It has quite a large number of use cases. This post will cover a few of them where using abstract types can help you ensure better type safety throughout your application. &lt;/p&gt;

&lt;p&gt;Let's dive into an example!&lt;/p&gt;

&lt;h2&gt;
  
  
  Tracking ID:s coming from an external API
&lt;/h2&gt;

&lt;p&gt;Imagine we have an API from which we retrieve organizations and users. We also have an API for updating a user's email. The type definitions for users and organizations might look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
  &lt;span class="n"&gt;name&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
  &lt;span class="n"&gt;email&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;organization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
  &lt;span class="n"&gt;name&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
  &lt;span class="n"&gt;users&lt;/span&gt;: &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've also made up a few API:s that we'll use for illustrative purposes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="nd"&gt;@val&lt;/span&gt;
&lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="n"&gt;getCurrentOrganization&lt;/span&gt;: &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;organization&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="s2"&gt;"getCurrentOrganization"&lt;/span&gt;

&lt;span class="nd"&gt;@val&lt;/span&gt;
&lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="n"&gt;setUserEmail&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;
  ~&lt;span class="n"&gt;email&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
  ~&lt;span class="n"&gt;id&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt;, &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"setUserEmail"&lt;/span&gt;

&lt;span class="nd"&gt;@val&lt;/span&gt;
&lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="n"&gt;getMe&lt;/span&gt;: &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"getMe"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The externals above binds to a few imaginary APIs: &lt;code&gt;getCurrentOrganization&lt;/code&gt; for retrieving the current contextual organization, &lt;code&gt;setUserEmail&lt;/code&gt; to set the email of a user via a user ID, and &lt;code&gt;getMe&lt;/code&gt; to retrieve the current user (me). &lt;/p&gt;

&lt;p&gt;Application code for updating the current users email might look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;me&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getMe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;currentOrganization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;getCurrentOrganization&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;, &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentOrganization&lt;/span&gt;

&lt;span class="nn"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Trying to update email for "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="n"&gt;me&lt;/span&gt;.&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;", in context of organization "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;".`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;setUserEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;~&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"some.fine.email@somedomain.com"&lt;/span&gt;, ~&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Yay, email updated!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This example uses &lt;a href="https://github.com/rescript-association/rescript-core" rel="noopener noreferrer"&gt;ReScript Core&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Excellent, this works well! Or wait... actually, it doesn't. Can you spot the error?&lt;/p&gt;

&lt;p&gt;We're accidentally passing the &lt;em&gt;organization&lt;/em&gt; &lt;code&gt;id&lt;/code&gt; to &lt;code&gt;setUserEmail&lt;/code&gt;, not the user id (&lt;code&gt;me.id&lt;/code&gt;). Shoot. At some point we destructured the &lt;code&gt;id&lt;/code&gt; from &lt;code&gt;currentOrganization&lt;/code&gt;, used it for something (probably logging), but then decided it wasn't necessary. But we forgot to remove it from the destructure, and now we're accidentally passing it to &lt;code&gt;setUserEmail&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Solving this is obviously easy - just pass &lt;code&gt;me.id&lt;/code&gt; instead. But what can we do to prevent this from happening again? &lt;/p&gt;

&lt;p&gt;An &lt;code&gt;id&lt;/code&gt; is a &lt;code&gt;string&lt;/code&gt;, that's how it comes back from the external API. Well, while it's true that it's a &lt;code&gt;string&lt;/code&gt; at runtime, we can tell the &lt;em&gt;type system&lt;/em&gt; it's something else, and then have the compiler help us ensure the above cannot happen. &lt;/p&gt;

&lt;p&gt;Here's how we can do that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Leveraging abstract types to control how values are used through your application
&lt;/h3&gt;

&lt;p&gt;Let's restructure our type definitions a bit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;organizationId&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;innerId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt;: &lt;span class="nn"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;,
  &lt;span class="n"&gt;name&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
  &lt;span class="n"&gt;email&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;organization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt;: &lt;span class="nn"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;organizationId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;,
  &lt;span class="n"&gt;name&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
  &lt;span class="n"&gt;users&lt;/span&gt;: &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We're adding two abstract types for the two types of ID:s we have, &lt;code&gt;userId&lt;/code&gt; and &lt;code&gt;organizationId&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We're adding a &lt;em&gt;module&lt;/em&gt; called &lt;code&gt;Id&lt;/code&gt;, with a single type &lt;code&gt;t&amp;lt;'innerId&amp;gt;&lt;/code&gt;. This looks a bit weird, and we could've skipped this and just used &lt;code&gt;userId&lt;/code&gt; and &lt;code&gt;organizationId&lt;/code&gt; directly. But, this is important for convenience. You'll see why a bit later.&lt;/li&gt;
&lt;li&gt;We change the &lt;code&gt;id&lt;/code&gt; fields for &lt;code&gt;user&lt;/code&gt; and &lt;code&gt;organization&lt;/code&gt; to be &lt;code&gt;Id.t&amp;lt;userId&amp;gt;&lt;/code&gt; and &lt;code&gt;Id.t&amp;lt;organizationId&amp;gt;&lt;/code&gt; respectively.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These changes are all at the &lt;em&gt;type level only&lt;/em&gt;. Nothing changes at runtime - every &lt;code&gt;id&lt;/code&gt; will still be a &lt;code&gt;string&lt;/code&gt;. We're just changing what the type system sees as we compile our application.&lt;/p&gt;

&lt;p&gt;As we try to compile this, we immediately catch the error we previously made:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;  &lt;span class="mi"&gt;39&lt;/span&gt; &lt;span class="err"&gt;┆&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;setUserEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;~&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"some.fine.email@somedomain.com"&lt;/span&gt;, ~&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nc"&gt;This&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt;: &lt;span class="nn"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;organizationId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nc"&gt;Somewhere&lt;/span&gt; &lt;span class="n"&gt;wanted&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's telling us that we're trying to pass an &lt;code&gt;Id.t&amp;lt;organizationId&amp;gt;&lt;/code&gt; where a &lt;code&gt;string&lt;/code&gt; is expected. That means two things to us:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We're catching the error we made previously - yay!&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setUserEmail&lt;/code&gt; is still expecting a &lt;code&gt;string&lt;/code&gt; for the user ID, but it should now expect our new &lt;code&gt;Id.t&amp;lt;userId&amp;gt;&lt;/code&gt; instead.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's change the type definition for the email updating API to expect the correct ID type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="nd"&gt;@val&lt;/span&gt;
&lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="n"&gt;setUserEmail&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;~&lt;span class="n"&gt;email&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;, ~&lt;span class="n"&gt;id&lt;/span&gt;: &lt;span class="nn"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt;, &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"setUserEmail"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There! Let's try to compile again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;  &lt;span class="mi"&gt;39&lt;/span&gt; &lt;span class="err"&gt;┆&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;setUserEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;~&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"some.fine.email@somedomain.com"&lt;/span&gt;, ~&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nc"&gt;This&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt;: &lt;span class="nn"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;organizationId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nc"&gt;Somewhere&lt;/span&gt; &lt;span class="n"&gt;wanted&lt;/span&gt;: &lt;span class="nn"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nc"&gt;The&lt;/span&gt; &lt;span class="n"&gt;incompatible&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;:
    &lt;span class="n"&gt;organizationId&lt;/span&gt; &lt;span class="n"&gt;vs&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Still doesn't compile obviously, but &lt;strong&gt;look at that error message&lt;/strong&gt;. It's telling us &lt;em&gt;exactly&lt;/em&gt; what's wrong - we're passing an &lt;code&gt;organizationId&lt;/code&gt; where we're supposed to pass a &lt;code&gt;userId&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;Fixing this is now a piece of cake:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;setUserEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;~&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"some.fine.email@somedomain.com"&lt;/span&gt;, ~&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;me&lt;/span&gt;.&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...and it compiles!&lt;/p&gt;

&lt;p&gt;Notice also that it's now impossible to pass anything else as &lt;code&gt;id&lt;/code&gt; to &lt;code&gt;setEmailUser&lt;/code&gt; than an &lt;code&gt;Id.t&amp;lt;userId&amp;gt;&lt;/code&gt;. And the only way to get an &lt;code&gt;Id.t&amp;lt;userId&amp;gt;&lt;/code&gt; is to call your external API retrieving a &lt;code&gt;user&lt;/code&gt;. Pretty neat.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hiding underlying values with abstract types
&lt;/h3&gt;

&lt;p&gt;Let's pause here for a moment. Remember that all changes we've made have been at the &lt;em&gt;type system level&lt;/em&gt;. Each &lt;code&gt;id&lt;/code&gt; is still just a &lt;code&gt;string&lt;/code&gt; at runtime. Doing &lt;code&gt;Console.log(me.id)&lt;/code&gt; would log a string. There's no such thing as a &lt;code&gt;Id.t&lt;/code&gt; when the code actually runs. We're just instructing the type system to track every type of ID and ensure it can't be used in any place we don't specifically allow.&lt;/p&gt;

&lt;p&gt;Also note that it's impossible to create an &lt;code&gt;Id.t&lt;/code&gt; yourself, even if you technically know that it's really a &lt;code&gt;string&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;: &lt;span class="nn"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"mock-id"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This produces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;  &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;: &lt;span class="nn"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"mock-id"&lt;/span&gt;

  &lt;span class="nc"&gt;This&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;
  &lt;span class="nc"&gt;Somewhere&lt;/span&gt; &lt;span class="n"&gt;wanted&lt;/span&gt;: &lt;span class="nn"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, again. Only way to get an &lt;code&gt;Id.t&amp;lt;userId&amp;gt;&lt;/code&gt; is to fetch a &lt;code&gt;user&lt;/code&gt; from your API.&lt;/p&gt;

&lt;p&gt;With just a few lines of code we've implemented a mechanism that can ensure that ID:s can't be used in any way we don't control, and that they can't be constructed in the application itself. &lt;/p&gt;

&lt;h3&gt;
  
  
  Accessing the underlying &lt;code&gt;string&lt;/code&gt; of the ID:s
&lt;/h3&gt;

&lt;p&gt;Moving on with the example, one question remain: Why have a module &lt;code&gt;Id&lt;/code&gt;, when we could just use the abstract types &lt;code&gt;userId&lt;/code&gt; and &lt;code&gt;organizationId&lt;/code&gt; directly? The error messages would be at least as good, and it'd achieve the same effect. &lt;/p&gt;

&lt;p&gt;Let's extend our example with what to do when you &lt;em&gt;do&lt;/em&gt; need to access the underlying value of something abstract, and why having a module like the &lt;code&gt;Id&lt;/code&gt; module we have is important for ergonomics.&lt;/p&gt;

&lt;p&gt;Imagine it suddenly got important for us to log the exact organization and user &lt;code&gt;id&lt;/code&gt; values before we attempt updating the email. We want our logging code to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="nn"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;`Trying to update email for user with id "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="n"&gt;me&lt;/span&gt;.&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;", in context of organization with id "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="n"&gt;currentOrganization&lt;/span&gt;.&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;".`&lt;/span&gt;,
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, this doesn't compile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;  &lt;span class="mi"&gt;37&lt;/span&gt; &lt;span class="err"&gt;┆&lt;/span&gt; &lt;span class="nn"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="mi"&gt;38&lt;/span&gt; &lt;span class="err"&gt;┆&lt;/span&gt;   &lt;span class="s2"&gt;`Trying to update email for user with id "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="n"&gt;me&lt;/span&gt;.&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;", in context of or
     ┆ ganization with id "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="n"&gt;currentOrganization&lt;/span&gt;.&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;".`&lt;/span&gt;,
  &lt;span class="mi"&gt;39&lt;/span&gt; &lt;span class="err"&gt;┆&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="mi"&gt;40&lt;/span&gt; &lt;span class="err"&gt;┆&lt;/span&gt; 

  &lt;span class="nc"&gt;This&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt;: &lt;span class="nn"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nc"&gt;Somewhere&lt;/span&gt; &lt;span class="n"&gt;wanted&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahh right. We're using the type system to hide the underlying type, but that goes two ways. That also means we can't use the ID by itself where we expect a &lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What if we could hide the fact that it's a &lt;code&gt;string&lt;/code&gt; to all of the application, but also have a way of turning any tracked id into a &lt;code&gt;string&lt;/code&gt;? That should be safe, because we know that any id comes from the API directly, and is guaranteed to be a &lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Turns out we can, and it's easy!&lt;/p&gt;

&lt;p&gt;Let's restructure our &lt;code&gt;Id&lt;/code&gt; module a bit again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Id&lt;/span&gt;: &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;innerId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;toString&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;innerId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;toString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quite a few new things happening here. Let's break them down one by one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We've added an inline &lt;em&gt;module signature&lt;/em&gt;, by writing &lt;code&gt;module Id: { ... } = { ... }&lt;/code&gt;. The signature says what we want &lt;em&gt;the outside&lt;/em&gt; to see when they look at this module. After it follows the actual implementation.&lt;/li&gt;
&lt;li&gt;The signature has &lt;code&gt;t&lt;/code&gt; as an abstract type, but the implementation aliases &lt;code&gt;t&lt;/code&gt; to &lt;code&gt;string&lt;/code&gt;. Uh-oh, aren't we leaking the underlying &lt;code&gt;string&lt;/code&gt; now? We're not, because in the &lt;em&gt;signature&lt;/em&gt; &lt;code&gt;t&lt;/code&gt; is still abstract, and that's what the outside sees.&lt;/li&gt;
&lt;li&gt;We've added a &lt;code&gt;toString&lt;/code&gt; function that takes an &lt;code&gt;Id.t&lt;/code&gt; and returns a &lt;code&gt;string&lt;/code&gt;, which is exactly what we needed. Two things to notice about this. First, the signature says it takes &lt;code&gt;Id.t&amp;lt;_&amp;gt;&lt;/code&gt; and produces a &lt;code&gt;string&lt;/code&gt;. &lt;code&gt;_&lt;/code&gt; in this case means "I don't care about the inner type" - &lt;code&gt;toString&lt;/code&gt; can be used on any &lt;code&gt;Id.t&lt;/code&gt;, it doesn't matter what inner type we've said it is, it's still a &lt;code&gt;string&lt;/code&gt; under the hood. Second, notice the difference between signature and implementation. The implementation just returns the id it was fed, since it knows it's really a &lt;code&gt;string&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The gist of the above is this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The outside world doesn't know what an &lt;code&gt;Id.t&lt;/code&gt; is (it's abstract), but it does know it can run &lt;code&gt;toString&lt;/code&gt; on it to get a &lt;code&gt;string&lt;/code&gt;, because the signature says so.&lt;/li&gt;
&lt;li&gt;The module itself knows that an &lt;code&gt;Id.t&lt;/code&gt; is &lt;em&gt;really&lt;/em&gt; a &lt;code&gt;string&lt;/code&gt;, and therefore that it's fine to just return itself when converting an &lt;code&gt;Id.t&lt;/code&gt; to a &lt;code&gt;string&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, with the &lt;code&gt;toString&lt;/code&gt; function, we can convert the ID:s in the log to strings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="nn"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;`Trying to update email for user with id "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="n"&gt;me&lt;/span&gt;.&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;", in context of organization with id "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="n"&gt;currentOrganization&lt;/span&gt;.&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;".`&lt;/span&gt;,
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There, it compiles! Note that this is only for going the &lt;em&gt;safe&lt;/em&gt; way of turning an &lt;code&gt;Id.t&lt;/code&gt; into a string. There's still no way to create a potentially unsafe &lt;code&gt;Id.t&lt;/code&gt; yourself in your application.&lt;/p&gt;

&lt;p&gt;And that's it. We're now fully controlling how the ID:s are used throughout our application. Pretty neat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;I'm a big believer in the importance of ergonomics - if it's too much hassle to use, people just won't use it. That's why this being easy and straight forward in ReScript is important. This is functionality I use often, and very much so because it's easy to use. Just define an abstract type, put it where you need it, and have the compiler rule out entire classes of potentially erroneous behavior.&lt;/p&gt;

&lt;p&gt;This post describes a scenario where I personally find reaching for abstract types very powerful. What use cases do you have where you use abstract types? Write in the comments!&lt;/p&gt;

&lt;p&gt;Thank you for reading.&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>ReScript, React and spread props - it's now possible!</title>
      <dc:creator>Gabriel Nordeborn</dc:creator>
      <pubDate>Sun, 19 Feb 2023 10:21:03 +0000</pubDate>
      <link>https://forem.com/zth/rescript-react-and-spread-props-its-now-possible-1k98</link>
      <guid>https://forem.com/zth/rescript-react-and-spread-props-its-now-possible-1k98</guid>
      <description>&lt;p&gt;&lt;a href="https://rescript-lang.org/blog/release-10-1" rel="noopener noreferrer"&gt;ReScript 10.1&lt;/a&gt; was recently released, bringing a new version of the built in JSX transform in ReScript. &lt;/p&gt;

&lt;p&gt;The new JSX transform brings a bunch of new capabilities, and one of those are that you can now do "props spreading". &lt;/p&gt;

&lt;p&gt;This post will quickly outline how you can use the new JSX version to bind to APIs that utilize props spreading. We'll assume you know what props spreading is, but if you don't, quickly read through the &lt;a href="https://reactjs.org/docs/jsx-in-depth.html#spread-attributes" rel="noopener noreferrer"&gt;official React documentation&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;More information about the new release, and JSX in ReScript:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://rescript-lang.org/blog/release-10-1#new-jsx-v4-syntax" rel="noopener noreferrer"&gt;The section in JSX v4 in the official blog post.
&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rescript-lang.org/docs/react/latest/elements-and-jsx" rel="noopener noreferrer"&gt;The official documentation on JSX in ReScript.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Example of using props spreading in bindings - binding &lt;code&gt;useFocus&lt;/code&gt; from &lt;code&gt;react-aria&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;We'll show how to utilize props spreading in ReScript and React by creating bindings to an actual API that uses props spreading, and porting the official JavaScript example code to ReScript from the documentation for that API.&lt;/p&gt;

&lt;p&gt;We're going to bind to &lt;a href="https://react-spectrum.adobe.com/react-aria/useFocus.html" rel="noopener noreferrer"&gt;&lt;code&gt;useFocus&lt;/code&gt;&lt;/a&gt; from &lt;a href="https://react-spectrum.adobe.com/react-aria" rel="noopener noreferrer"&gt;&lt;code&gt;react-aria&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You're encouraged to skim the &lt;a href="https://react-spectrum.adobe.com/react-aria/useFocus.html" rel="noopener noreferrer"&gt;&lt;code&gt;useFocus&lt;/code&gt; documentation page&lt;/a&gt; before continuing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the bindings
&lt;/h2&gt;

&lt;p&gt;First, let's set up our bindings for &lt;code&gt;useFocus&lt;/code&gt; from &lt;code&gt;react-aria&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Reading the documentation, we see both what the function returns, and the config it takes: &lt;a href="https://react-spectrum.adobe.com/react-aria/useFocus.html#usage" rel="noopener noreferrer"&gt;https://react-spectrum.adobe.com/react-aria/useFocus.html#usage&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Writing the return and input types in ReScript from that documentation page looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;useFocusConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;onFocus&lt;/span&gt;?: &lt;span class="nn"&gt;JsxEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Focus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;,
  &lt;span class="n"&gt;onBlur&lt;/span&gt;?: &lt;span class="nn"&gt;JsxEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Focus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;,
  &lt;span class="n"&gt;onFocusChange&lt;/span&gt;?: &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;useFocusReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;focusProps&lt;/span&gt;: &lt;span class="nn"&gt;JsxDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;domProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice 2 things here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JsxEvent.Focus.t is the equivalent of FocusEvent in TypeScript.&lt;/li&gt;
&lt;li&gt;The return type holds one field only, focusProps. That's typed as a JsxDOM.domProps because it's a bag of props that you should apply on the JSX DOM element where you want the focus handlers from useFocus. This is important and is what enables the props spread. More about this further down.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's tie together the types with a binding to the hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="nd"&gt;@module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"react-aria"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="n"&gt;useFocus&lt;/span&gt;: &lt;span class="n"&gt;useFocusConfig&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;useFocusReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"useFocus"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The finished binding looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// We're saving this in the file ReactAria.res&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;useFocusConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;onFocus&lt;/span&gt;?: &lt;span class="nn"&gt;JsxEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Focus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;,
  &lt;span class="n"&gt;onBlur&lt;/span&gt;?: &lt;span class="nn"&gt;JsxEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Focus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;,
  &lt;span class="n"&gt;onFocusChange&lt;/span&gt;?: &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;useFocusReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;focusProps&lt;/span&gt;: &lt;span class="nn"&gt;JsxDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;domProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"react-aria"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="n"&gt;useFocus&lt;/span&gt;: &lt;span class="n"&gt;useFocusConfig&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;useFocusReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"useFocus"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Porting the example JavaScript code to ReScript
&lt;/h2&gt;

&lt;p&gt;There! We have the types and the binding to the hook. Let's see if we can implement the same example that the react-aria documentation has. Here's the example, in regular JavaScript, as it's shown in the documentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;useFocus&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-aria&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEvents&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;focusProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useFocus&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;onFocus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nf"&gt;setEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;focus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;onBlur&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nf"&gt;setEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blur&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;onFocusChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isFocused&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nf"&gt;setEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;`focus change: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;isFocused&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;example&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Example&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
        &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;focusProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;example&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt;
        &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
          &lt;span class="na"&gt;maxHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;200px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's implement it in ReScript using our new binding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@react.component&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;, &lt;span class="n"&gt;setEvents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="c1"&gt;// We put the `useFocus` binding code in a `ReactAria.res` file.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;focusProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;ReactAria&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;useFocus&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="n"&gt;onFocus&lt;/span&gt;: &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;setEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;"focus"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;,
      &lt;span class="n"&gt;onBlur&lt;/span&gt;: &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;setEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;"blur"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;,
      &lt;span class="n"&gt;onFocusChange&lt;/span&gt;: &lt;span class="n"&gt;isFocused&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;setEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
          &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;`focus change: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="n"&gt;isFocused&lt;/span&gt; ? &lt;span class="s2"&gt;"true"&lt;/span&gt; : &lt;span class="s2"&gt;"false"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;,
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="n"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"example"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"Example"&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;...&lt;span class="n"&gt;focusProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ul&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nn"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;~&lt;span class="n"&gt;maxHeight&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"200px"&lt;/span&gt;, ~&lt;span class="n"&gt;overflow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"auto"&lt;/span&gt;, &lt;span class="p"&gt;())}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapWithIndex&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;, &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;li&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things to notice about the ReScript code above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We moved the binding code to a separate file &lt;code&gt;ReactAria.res&lt;/code&gt;, and access our binding via &lt;code&gt;ReactAria.useFocus&lt;/code&gt;. This is common practice, grouping your bindings in a separate file when it makes sense.&lt;/li&gt;
&lt;li&gt;It uses &lt;a href="https://github.com/rescript-association/rescript-core" rel="noopener noreferrer"&gt;ReScript Core&lt;/a&gt; for the &lt;code&gt;Array&lt;/code&gt; functions.&lt;/li&gt;
&lt;li&gt;Also notice that there's not a single type annotation in here, but the code is 100% sound/type safe thanks to ReScript's great inference.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, just like in the JavaScript code, we spread &lt;code&gt;{...focusProps}&lt;/code&gt; on the &lt;code&gt;&amp;lt;input /&amp;gt;&lt;/code&gt;. This works because focusProps has the type &lt;code&gt;JsxDOM.domProps&lt;/code&gt;, and that's the same type that &lt;code&gt;&amp;lt;input /&amp;gt;&lt;/code&gt; expects its props to have.&lt;/p&gt;

&lt;p&gt;This is key to why this works - it's essentially the equivalent of spreading props on a record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;inputProps&lt;/span&gt;: &lt;span class="nn"&gt;JsxDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;domProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;...&lt;span class="n"&gt;focusProps&lt;/span&gt;, &lt;span class="n"&gt;id&lt;/span&gt;: &lt;span class="s2"&gt;"example"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Summing up this quick post - whenever you're binding to something that wants you to use spread props on JSX DOM elements, type that as &lt;code&gt;JsxDom.domProps&lt;/code&gt; so it matches what JSX DOM elements expect for props.&lt;/p&gt;

&lt;p&gt;That's it! Here's a few additional links if you're interested in diving deeper:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://rescript-lang.org/docs/manual/latest/record#immutable-update" rel="noopener noreferrer"&gt;Spreading in records&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rescript-lang.org/docs/react/latest/elements-and-jsx" rel="noopener noreferrer"&gt;Main docs about JSX in ReScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rescript-lang.org/docs/react/latest/migrate-react" rel="noopener noreferrer"&gt;Migration guide from JSX v3 to JSX v4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reactjs.org/docs/jsx-in-depth.html#spread-attributes" rel="noopener noreferrer"&gt;React documentation on spread props&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>showdev</category>
    </item>
    <item>
      <title>Getting rid of your dead code in ReScript</title>
      <dc:creator>Gabriel Nordeborn</dc:creator>
      <pubDate>Mon, 24 Oct 2022 16:14:11 +0000</pubDate>
      <link>https://forem.com/zth/getting-rid-of-your-dead-code-in-rescript-3mba</link>
      <guid>https://forem.com/zth/getting-rid-of-your-dead-code-in-rescript-3mba</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Exploring ReScript's tools for eliminating dead code, keeping your repository clean and without unnecessary distractions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dead code is code that's left in your repository but never actually used in your application. &lt;/p&gt;

&lt;p&gt;Other than occupying unnecessary space and adding to compilation times, dead code can also be distracting and confusing when you look at it thinking it's used in the application. Like when bending the new thing you're building to work with an existing abstraction that's not in use, and should be deleted instead. Or refactoring a component to work with something new you're working on, but the component itself is unused in the application and should be removed.&lt;/p&gt;

&lt;p&gt;ReScript has some quite advanced and convenient tools for dealing with dead code. In this article we're going to explore how you can get started using them to keep your repository clean and free of the potential distractions of left behind dead code.&lt;/p&gt;

&lt;p&gt;We'll explore dead code analysis in ReScript by running the analysis on a real, fairly large production code base that's in active development. This will uncover concrete and interesting real life examples of how the analysis can help remove dead code and reduce the complexity of the code base.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Dead Code Analysis
&lt;/h2&gt;

&lt;p&gt;Dead code analysis is about tracking types and values throughout your program &lt;em&gt;at compile time&lt;/em&gt;, figuring out how (and if) they're actually used. Depending on your language and type system, this can be quite tricky, and in many cases impossible to get 100% right.&lt;/p&gt;

&lt;p&gt;Whether some piece of code is dead or not can be subtle. Simple cases are easy - a function that is never called, or a value that is never used. The more complicated cases however are much harder. What about record fields that are never read? Or variant cases that are handled in your code, but never actually constructed at runtime?&lt;/p&gt;

&lt;p&gt;In ReScript, we're lucky. A bunch of language design decisions and language features come together in a way that makes dead code analysis both effective and accurate.&lt;/p&gt;

&lt;p&gt;Baked into the ReScript VSCode extension is the ReScript Code Analyzer. This code analyzer (also called &lt;code&gt;reanalyze&lt;/code&gt;) is an advanced statical analysis tool for ReScript built by core team member Cristiano Calcagno. Cristiano has an extensive background in statical analysis, both in academia and in practice.&lt;/p&gt;

&lt;p&gt;The code analyzer works by continuously analyzing your entire code base. Any issue found is reported right in the editor's "Problems" pane. It's easy to start, easy to stop, and is really fast given the amount of work it's doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Enough background, let's get started! You'll need version &lt;code&gt;&amp;gt;=1.8.2&lt;/code&gt; of the VSCode extension.  &lt;/p&gt;

&lt;p&gt;You activate the analysis in the ReScript VSCode extension by running the command &lt;code&gt;&amp;gt; ReScript: Start Code Analyzer&lt;/code&gt; (&lt;code&gt;Cmd/Ctrl + P&lt;/code&gt; brings up the command palette).&lt;/p&gt;

&lt;p&gt;Stopping the analysis is a matter of either running the command &lt;code&gt;&amp;gt; ReScript: Stop Code Analyzer&lt;/code&gt;, or clicking the "Stop Code Analyzer" button in the status bar that's visible when the code analyzer is active.&lt;/p&gt;

&lt;p&gt;Once you've started the code analysis, you should see the "Problems" pane being populated with various warnings and errors related to dead code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu0s8iifb7wb9qiuk16m3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu0s8iifb7wb9qiuk16m3.png" alt="Example of the VSCode extension "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's possible to do fine grained configuration of the analysis if you'd like. You can configure things like suppressing reporting for entire sub folders, and so on. Quite useful, and we'll cover configuration of the analysis at the end of this article.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Examples from real life
&lt;/h2&gt;

&lt;p&gt;Let's look at some concrete cases of dead code that the analysis is finding in the real production code base we're looking in, and how fixing them helps us clean up the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Record fields that are never used
&lt;/h3&gt;

&lt;p&gt;Since records are nominal, each defined field will always be available. But what about fields that are never actually read? Let's look at an example.&lt;/p&gt;

&lt;p&gt;There's a &lt;code&gt;CheckBoxList.res&lt;/code&gt; file. This file has a React hook that returns a record with a bunch of helpers for dealing with the state for a list of check boxes. The return type looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;useReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;items&lt;/span&gt;: &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;,
  &lt;span class="n"&gt;toggleItemChecked&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;,
  &lt;span class="n"&gt;setCheckedOnItem&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;, &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;,
  &lt;span class="n"&gt;checkAll&lt;/span&gt;: &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;,
  &lt;span class="n"&gt;uncheckAll&lt;/span&gt;: &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the analysis tells us: &lt;code&gt;useReturn.toggleItemChecked is a record label never used to read a value&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So, &lt;code&gt;toggleItemChecked&lt;/code&gt; is never actually used by any of the code using the hook. We can safely remove that. And removing that allows us to remove the underlying code for the function, getting rid of a little bit of complexity in that hook. Nice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Variant cases that are never used
&lt;/h3&gt;

&lt;p&gt;What about variant cases that are defined, accounted for the in the code, but never actually used in the application? Let's look at a concrete example.&lt;/p&gt;

&lt;p&gt;There's a React component called &lt;code&gt;&amp;lt;Menu /&amp;gt;&lt;/code&gt;. It renders a pop-over menu. The menu takes an array of &lt;code&gt;item&lt;/code&gt;, and the type definition of these items look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;textType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;TextWithIcon&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;icon&lt;/span&gt;: &lt;span class="nn"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;, &lt;span class="n"&gt;text&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Href&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;HeadlessUi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;itemChildrenRenderProps&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;disabled&lt;/span&gt;: &lt;span class="kt"&gt;bool&lt;/span&gt;,
  &lt;span class="n"&gt;text&lt;/span&gt;: &lt;span class="n"&gt;textType&lt;/span&gt;,
  &lt;span class="n"&gt;href&lt;/span&gt;: &lt;span class="n"&gt;href&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essentially, we have an item that can have &lt;code&gt;text&lt;/code&gt; to render the text for the menu item, and a &lt;code&gt;href&lt;/code&gt; to deal with rendering the link for the menu item.&lt;/p&gt;

&lt;p&gt;As we run the analysis, two things are reported:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;textType.Render is a variant case which is never constructed&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;href.Render is a variant case which is never constructed&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Interesting! It appears that &lt;code&gt;Render&lt;/code&gt;, which is an escape hatch in this component for essentially "rendering what you want" for text and linking, is never actually used in the code base. That means there's no place in the entire app that's configuring a menu item to use &lt;code&gt;Render&lt;/code&gt; for &lt;code&gt;text&lt;/code&gt;, or for &lt;code&gt;href&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, I can remove those two variant cases. However, removing them per se isn't the nice thing - it's that I can now remove the code in the component that handles &lt;code&gt;Render&lt;/code&gt;. And in this specific case, removing the code handling &lt;code&gt;Render&lt;/code&gt; meant being able to reduce the complexity of the component quite a lot.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Notice the level of granularity in the analysis that the code analyzer is capable of doing. It's finding a variant case, and making a distinction between that variant case being &lt;em&gt;consumed&lt;/em&gt; (which it is inside of the component, since we account for it as we're rendering) and it being &lt;em&gt;constructed&lt;/em&gt;, meaning someone actually using that specific variant case somewhere in the code when defining menu items. Quite powerful.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Unused parts of React state
&lt;/h3&gt;

&lt;p&gt;This one was quite interesting. The app has a form for changing password for the user, &lt;code&gt;ChangePasswordForm.res&lt;/code&gt;. That form has its state defined like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;validationState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Idle&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Invalid&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Valid&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;oldPassword&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
  &lt;span class="n"&gt;newPassword&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
  &lt;span class="n"&gt;newPasswordRepeated&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
  &lt;span class="n"&gt;validationState&lt;/span&gt;: &lt;span class="n"&gt;validationState&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It then uses a reducer to manipulate that state. Notice &lt;code&gt;validationState&lt;/code&gt; here. This was all hooked up nicely in the form - validation states were produced as the form was changed, and so on. &lt;em&gt;However&lt;/em&gt;, dead code analysis tells us a different story - &lt;code&gt;validationState is a record label never used to read a value&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hmmm... It turns out that while the component does produce the right validation states for the various scenarios, it's never using the validation state anywhere. It's just setting it.&lt;/p&gt;

&lt;p&gt;Apparently producing the validation state was part of how the form used to work. But, it was refactored at some point to not use that validation state, and rather just look at if things were valid via another mechanism on submit. Someone just forgot to remove it from the state and the surrounding logic for producing it.&lt;/p&gt;

&lt;p&gt;This, while rather small, is a prime example of distractions and the potentially dangerous confusion that can come from dead code. You won't catch that the validation state isn't used by just looking at this component quickly. And if you don't catch that, refactoring or building out this component means you're likely to take the validation state and its logic into account. &lt;/p&gt;

&lt;p&gt;And that might cause you to build a more complicated solution for the thing you're doing, slow you down, and so on. Dangerous.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unnecessarily exposed functions in an interface file
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;DrilldownTarget.resi&lt;/code&gt; has two reports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MetricParam.parse is never used&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MetricParam.serialize is never used&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These both indicate that for the interface file, &lt;code&gt;parse&lt;/code&gt; and &lt;code&gt;serialize&lt;/code&gt; from the &lt;code&gt;MetricParam&lt;/code&gt; sub module is exposed to the outside world, but nobody is actually using them. So, it's safe to remove them from the interface.&lt;/p&gt;

&lt;p&gt;A small thing, but helpful to avoid unnecessarily exposing them.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But what if you &lt;em&gt;do&lt;/em&gt; want to expose them even if nobody is currently using them? We'll cover how to tell the code analyzer about that later on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Regular dead code
&lt;/h3&gt;

&lt;p&gt;It's also finding quite a few functions that are just never called. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;RouterUtils.res&lt;/code&gt; has a bunch of helpers around constructing and handling URL:s. The analysis is telling us the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;routerUrlToPath is never used&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;routeUrlStartsWith is never used&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Removing them uncovers a number of other helpers in that file that are no longer needed. The end result is a much thinner &lt;code&gt;RouterUtils.res&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unused React components
&lt;/h3&gt;

&lt;p&gt;It's finding a number of unused React components. Some of them I want to keep because I know they'll be used in the future (more on how to tell the code analyzer below). But, many of them can be removed. They're old and outdated. It's just that nobody had removed them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Living with the dead
&lt;/h2&gt;

&lt;p&gt;Sometimes removing the dead code isn't what you want. It might be code that happens to be dead at this moment, but that you know will be used later. Or code that while not used right now still serves a purpose in terms of being illustrative of a particular use case. And so on.&lt;/p&gt;

&lt;p&gt;The code analyzer understands 2 annotations for suppressing dead code reporting at a more granular level. These are &lt;code&gt;@live&lt;/code&gt; and &lt;code&gt;@dead&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;We're going to talk a bit about the difference between &lt;code&gt;@live&lt;/code&gt; and &lt;code&gt;@dead&lt;/code&gt; soon. There's some subtle nuance between them. But, first let's look at a number of examples of how you can add these annotations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// `Small` is never constructed in the code base as of now, but I know it will be later, so I can annotate just that variant case&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;XSmall&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;@dead&lt;/span&gt; &lt;span class="nc"&gt;Small&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Medium&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Large&lt;/span&gt;

&lt;span class="c1"&gt;// `age` is never read in the code base right now, but I know it will be eventually, so I don't care that it's considered dead as of now&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;name&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
  &lt;span class="nd"&gt;@dead&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;: &lt;span class="kt"&gt;int&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// This entire type isn't used right now, but I need to keep it around regardless&lt;/span&gt;
&lt;span class="nd"&gt;@live&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;isCat&lt;/span&gt;: &lt;span class="kt"&gt;bool&lt;/span&gt;,
  &lt;span class="n"&gt;owner&lt;/span&gt;: &lt;span class="n"&gt;user&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// This function also isn't used right now, but I want to keep it around regardless of that&lt;/span&gt;
&lt;span class="nd"&gt;@live&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getUserName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;.&lt;span class="n"&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Notice how you can add these annotations at a granular level.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, with that out of the way - what's the difference between &lt;code&gt;@live&lt;/code&gt; and &lt;code&gt;@dead&lt;/code&gt;?&lt;/p&gt;

&lt;h4&gt;
  
  
  @dead - when something is dead, but you intend to fix it
&lt;/h4&gt;

&lt;p&gt;Adding &lt;code&gt;@dead&lt;/code&gt; to something will suppress dead code reports for that piece of code. If that code comes alive (as in it's used again), the code analyzer will tell you that the piece of code you've marked as dead is actually alive now. &lt;/p&gt;

&lt;p&gt;This is useful because it'll allow you to remove dead code suppressions when they're no longer useful.&lt;br&gt;
over.&lt;/p&gt;
&lt;h4&gt;
  
  
  @live - when something is potentially dead but you want to keep it around regardless
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;@live&lt;/code&gt; annotation will also suppress dead code reports, but it won't tell you if the thing you're suppressing becomes alive again. Additionally, it'll also keep anything &lt;em&gt;using it&lt;/em&gt; alive. It'll essentially force the dead code analysis to behave as if the code is alive for real.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configuration of the analysis
&lt;/h3&gt;

&lt;p&gt;You can configure the analysis in &lt;code&gt;bsconfig.json&lt;/code&gt;. Let's examplify by looking at the configuration for the project we just ran the analysis for. Here are the relevant parts of &lt;code&gt;bsconfig.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reanalyze"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"analysis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"dce"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"suppress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"src/bindings"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/stories"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/routes"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"unsuppress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"transitive"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's go through what we're configuring.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;analysis&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;This tells the code analyzer what analysis you want to run. &lt;code&gt;dce&lt;/code&gt; means &lt;code&gt;Dead Code Elimination&lt;/code&gt;, and is what we'll be focusing on in this article. There are more analysis you can activate (most notably &lt;code&gt;exception&lt;/code&gt;). We're going to cover them in later articles.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;suppress&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;This lets you suppress dead code &lt;em&gt;reports&lt;/em&gt; for entire subfolders and specific files in your project. Note that it's just suppressing the reports, the analysis still takes place. So a suppressed folder might be keeping code alive in a folder where you do want reports.&lt;/p&gt;

&lt;p&gt;Useful for ignoring dead code in places where you don't care, or in places where you can't fix the dead code anyway (generated code being a classic example). &lt;/p&gt;

&lt;p&gt;We're ignoring our bindings folder with hand rolled bindings. We're also ignoring both &lt;code&gt;stories&lt;/code&gt; and &lt;code&gt;routes&lt;/code&gt; because those contain things that are either a) mostly generated, or b) irrelevant that they're dead. For example, Storybook stories are considered dead because they're never actually used in the main app. But we don't mind that.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;unsuppress&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;There's nothing configured here right now, but this entry allows you to unsuppress reporting for specific files in the suppressed folders. Handy for certain cases.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;transitive&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;This one is important, because it controls whether code that's &lt;em&gt;transitively&lt;/em&gt; dead is reported or not. "Transitively dead" is a mouthful. It essentially means code that's dead because all of the code that's using it is dead.&lt;/p&gt;

&lt;p&gt;Setting this to &lt;code&gt;true&lt;/code&gt; means you'll immediately see &lt;em&gt;all&lt;/em&gt; the dead code in your repository. That's useful for certain scenarios, like overviewing how much dead code you have in total. However, it's not very user friendly, because you won't know the full story of &lt;em&gt;why&lt;/em&gt; the code is dead. So, it's not technically dead by itself because other code is still referencing it, but it's considered dead because the code referencing it is dead itself.&lt;/p&gt;

&lt;p&gt;The default is &lt;code&gt;false&lt;/code&gt;. That's most useful for when you're going to be working with removing your dead code. Doing that means that you'll only get reports of dead code for things that is dead by itself, and not because everything using it is dead. &lt;/p&gt;

&lt;p&gt;That is useful because you'll be able to remove the dead code that's reported, and your program will still compile after. You'll be able to remove "layers" of dead code at a time. &lt;/p&gt;

&lt;p&gt;This is important for a number of practical reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It makes it easy to trust the tool - your program will still compile after removing the code the tool is saying is dead&lt;/li&gt;
&lt;li&gt;It makes it easy to remove dead code &lt;em&gt;incrementally&lt;/em&gt;. This is very important, because this means you can clean up your repository little by little, over time. Much easier than being faced with all the dead code at once, with no clear indication of what to remove first&lt;/li&gt;
&lt;li&gt;It helps you not get overwhelmed. Even if you have thousands of cases of dead code, a large majority of them are probably going to be dead only because the code using them is also dead, and you couldn't remove them in isolation anyway. This approach makes sure you don't even need to think about those cases until they're relevant.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;This type of functionality is in my opinion one of the unique selling points of a language like ReScript. Fine grained, accurate and efficient dead code analysis. It's possible because of the design and simplicity of the language. And because of the type system. &lt;/p&gt;

&lt;p&gt;A great example of using the language's strengths to build something pragmatic and useful in the real world. You &lt;em&gt;need&lt;/em&gt; help from the computer to do these types of things. Over time it's impossible to not accidentally miss removing code that's no longer in use. Especially in the more complicated cases, like we saw in the example of the form with with the unused validation state.&lt;/p&gt;

&lt;p&gt;Tools for dealing with these things need to be pragmatic. What are we trying to get done? Dead code can exist for various reasons, and like we've seen it's not always the right decision to remove it. That's why our focus is on building tools that help you improve your code base and situation one small step at a time.&lt;/p&gt;

&lt;p&gt;There, you know all about dead code analysis in ReScript now! Go try it in your own code bases and see what comes out.&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A special shout out to &lt;a href="https://package.elm-lang.org/packages/jfmengels/elm-review/latest/" rel="noopener noreferrer"&gt;Elm review&lt;/a&gt; which has inspired how &lt;code&gt;reanalyze&lt;/code&gt; reports code that's transitively dead.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>rescript</category>
    </item>
    <item>
      <title>Speeding up ReScript compilation using interface files</title>
      <dc:creator>Gabriel Nordeborn</dc:creator>
      <pubDate>Thu, 20 Oct 2022 16:18:52 +0000</pubDate>
      <link>https://forem.com/zth/speeding-up-rescript-compilation-using-interface-files-4fgn</link>
      <guid>https://forem.com/zth/speeding-up-rescript-compilation-using-interface-files-4fgn</guid>
      <description>&lt;p&gt;&lt;a href="https://rescript-lang.org/"&gt;ReScript&lt;/a&gt; compilation speeds are really fast out of the box. But, sometimes editing certain files can take longer to compile than you'd expect it to. &lt;/p&gt;

&lt;p&gt;In this article we'll explore a strategy for speeding up compilation by leveraging interface files. We'll also dive into &lt;em&gt;why&lt;/em&gt; using interface files can speed up compilation. And, by doing that we'll dig a bit into how the ReScript compiler works internally.&lt;/p&gt;

&lt;p&gt;Let's start from the beginning though, with a few concepts that are necessary to understand to be able to follow the rest of the article. You can skip the coming sections if you're already familiar with modules, interfaces and implementation files in ReScript.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLDR;&lt;/strong&gt; If you have files that, when edited, cause longer compile times than you'd expect, see if adding interface files for those files help. If you're changing the implementation often, but not the interface, you might see massive speed increases from adding interface files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modules and files
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Read the official docs on modules: &lt;a href="https://rescript-lang.org/docs/manual/latest/module"&gt;Modules in ReScript&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Quoting the official docs, "modules are like mini files!". A module is a collection of types, values, functions, and so on.&lt;/p&gt;

&lt;p&gt;For this article's sake, pay special attention to the fact that every &lt;em&gt;file&lt;/em&gt; is automatically a module. So, if you have &lt;code&gt;MyFile.res&lt;/code&gt;, that file's contents will be available for you to use under the &lt;code&gt;MyFile&lt;/code&gt; module globally.&lt;/p&gt;

&lt;p&gt;We'll use the words module and file interchangeably, so please keep in mind that every file is a module.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation and interface files
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Read the official docs: &lt;a href="https://rescript-lang.org/docs/gentype/latest/usage#interface-resi-and-implementation-res-files"&gt;Interface and implementation files in ReScript&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ReScript lets you separate interface and implementation in various ways. &lt;/p&gt;

&lt;p&gt;Interface here means a description of what the outside world has access to in your module. This is typically called the &lt;em&gt;signature&lt;/em&gt; of the code. It's essentially type information.&lt;/p&gt;

&lt;p&gt;Implementation means the code you write to fulfill that description. &lt;/p&gt;

&lt;p&gt;A simple example: in your interface, you tell the world there's going to be a value called &lt;code&gt;usernames&lt;/code&gt; available that's an array of strings. And in the implementation, you produce that actual array of strings called &lt;code&gt;usernames&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AllUsers.resi&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;usernames&lt;/span&gt;: &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AllUsers.res&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;usernames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;allUsersInSystem&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Belt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;.&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the outside world doesn't need to care about &lt;em&gt;how&lt;/em&gt; the &lt;code&gt;usernames&lt;/code&gt; array is produced. That's the &lt;em&gt;implementation&lt;/em&gt;. It just needs to know that that array will be there.&lt;/p&gt;

&lt;p&gt;In ReScript, implementation files are suffixed with &lt;code&gt;.res&lt;/code&gt;, and interface files are suffixed with &lt;code&gt;.resi&lt;/code&gt;. So, if you have &lt;code&gt;AllUsers.res&lt;/code&gt;, you add an interface by adding a &lt;code&gt;AllUsers.resi&lt;/code&gt; file.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, how can interface files speed up compilation?
&lt;/h2&gt;

&lt;p&gt;Why does all of this matter to compilation speed? Let's dive into how the ReScript compiler works a bit.&lt;/p&gt;

&lt;p&gt;When you make a change to your code and then recompile, the ReScript compiler needs to type check all affected parts of your program to make sure everything still adds up. The ReScript compiler is quite intelligent and mostly knows how to check the minimum set of files needed as you change things. This is a huge part of what makes the compiler so fast.&lt;/p&gt;

&lt;p&gt;Type checking is, very simplified, about ensuring that all the types match each other in the project. Is the parts of your program expecting (and receiving) the right things?&lt;/p&gt;

&lt;p&gt;The compiler looks at each file (module), and then does one of two things depending on whether that file has an interface file or not.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If it has an interface file, the compiler checks the implementation file to make sure that the implementation matches the interface. Are you delivering what you promised in the interface? If all checks out, it moves on. If not, it errors.&lt;/li&gt;
&lt;li&gt;If it doesn't have an interface file, the compiler needs to derive an interface by itself for the file by looking at the implementation file directly. So it looks at the code you've written, infers the signature of that code ("&lt;code&gt;let myArray = ["some string"]&lt;/code&gt; is an array of strings"), and then uses that inferred signature as an interface for that file as it moves on. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And this is because the type checker works on the type information from the &lt;em&gt;interface&lt;/em&gt;, not on the actual code implementing that interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compilation slows down because the compiler needs to derive the interface again and again
&lt;/h2&gt;

&lt;p&gt;This is what it all comes down to. If there's no interface file, the compiler needs to derive that interface itself by looking at the implementation. &lt;/p&gt;

&lt;p&gt;And it needs to do that every time the file changes.&lt;/p&gt;

&lt;p&gt;And after it has done that, it needs to recheck all of the modules depending on the file you changed to make sure things still type check.&lt;/p&gt;

&lt;p&gt;But, if there is an interface file, all the compiler needs to check is that your implementation still matches the interface. It doesn't need to check anything else. It can safely assume that any other file that's depending on this file and has compiled successfully with the current interface is still valid. Because the &lt;em&gt;interface&lt;/em&gt; hasn't changed, just the implementation for that interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  A good strategy for interface files
&lt;/h2&gt;

&lt;p&gt;How much you make use of interface files or not is largely a philosophical question that I'm going to refrain from discussing here. Some people never use them. Some people use them a lot. I personally use them some, but not a lot.&lt;/p&gt;

&lt;p&gt;One strategy I will leave you with though is to be mindful of modules you have that are used by many other modules. Those might be a good idea to use interface files for, not the least because of the speed benefits discussed in this article.&lt;/p&gt;

&lt;p&gt;So, be mindful of when editing certain files cause longer compilation times than you'd expect. See if adding an interface file might help.&lt;/p&gt;

&lt;h2&gt;
  
  
  Editor tooling helps make life with interface files easier
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/rescript-lang/rescript-vscode"&gt;ReScript VSCode extension&lt;/a&gt; has two goodies that help make life with interface files easier that I want to mention.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automatically generating an interface file from an implementation file
&lt;/h3&gt;

&lt;p&gt;If you have a &lt;code&gt;.res&lt;/code&gt; file that you want to create an interface file for, you can use the command &lt;code&gt;&amp;gt; ReScript: Create an interface file for this implementation file&lt;/code&gt; (&lt;code&gt;Cmd/Ctrl + P&lt;/code&gt; brings up the command prompt). You'll get a fully filled out &lt;code&gt;.resi&lt;/code&gt; file right next to your &lt;code&gt;.res&lt;/code&gt; file that you can edit to your liking.&lt;/p&gt;

&lt;p&gt;Quite convenient.&lt;/p&gt;

&lt;h3&gt;
  
  
  Switching between interface and implementation files
&lt;/h3&gt;

&lt;p&gt;The extension makes it easy to jump between the &lt;code&gt;.res&lt;/code&gt; and &lt;code&gt;.resi&lt;/code&gt; file for a module via the command &lt;code&gt;&amp;gt; ReScript: Switch implementation/interface&lt;/code&gt;. Running that command will jump to the &lt;code&gt;.resi&lt;/code&gt; file if you're in a &lt;code&gt;.res&lt;/code&gt; file (and the &lt;code&gt;.resi&lt;/code&gt; file exists of course), and running it from a &lt;code&gt;.resi&lt;/code&gt; file will jump to the corresponding &lt;code&gt;.res&lt;/code&gt; file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;There's a ton more to say when it comes to what you can use interface files for, both in terms of features, but also in terms of techniques for a good developer workflow. This article focuses on the performance aspects of interface files, but I'm likely going to cover the other points too at some point.&lt;/p&gt;

&lt;p&gt;Until then, thank you for reading!&lt;/p&gt;

</description>
      <category>rescript</category>
      <category>compilers</category>
      <category>performance</category>
    </item>
    <item>
      <title>Announcing Relay Meetup, a global, remote meetup for Relay, the GraphQL client</title>
      <dc:creator>Gabriel Nordeborn</dc:creator>
      <pubDate>Mon, 05 Oct 2020 18:10:54 +0000</pubDate>
      <link>https://forem.com/zth/announcing-relay-meetup-a-global-remote-meetup-for-relay-the-graphql-client-5geo</link>
      <guid>https://forem.com/zth/announcing-relay-meetup-a-global-remote-meetup-for-relay-the-graphql-client-5geo</guid>
      <description>&lt;p&gt;I'm very excited to announce &lt;a href="https://relaymeetup.com"&gt;RelayMeetup.com&lt;/a&gt; - a remote meetup dedicated to Relay, the GraphQL client. &lt;/p&gt;

&lt;p&gt;Every month we'll host an online meetup full of interesting and hands-on content on Relay. Each meetup will feature one or more &lt;em&gt;talks&lt;/em&gt;, and a &lt;em&gt;theme&lt;/em&gt;. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The talks can be about anything as long as it has some connection to Relay. Presentations, interviews, live demo/coding sessions - anything goes!&lt;/li&gt;
&lt;li&gt;The themes will cover aspects of using Relay hands-on. We'll focus on practical knowledge and real life examples - bringing as actionable content as we can.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We want to create a friendly, laid back and natural space where anyone curious about Relay can feel at home. We'll stream live on YouTube, and everyone is welcome to either join live or watch the recorded event afterwards.&lt;/p&gt;

&lt;h2&gt;
  
  
  The time for Relay is now
&lt;/h2&gt;

&lt;p&gt;People who spend enough time to learn Relay in depth tend to fall in love with it. There's truly no alternative in the GraphQL client space that offers what Relay offers. And, with the &lt;a href="https://relay.dev/docs/en/experimental/a-guided-tour-of-relay"&gt;upcoming hook APIs&lt;/a&gt;, fully leveraging suspense and concurrent mode, Relay is as relevant as ever.&lt;/p&gt;

&lt;p&gt;The Relay community is vibrant and full of activity. But it's still small. Adoption isn't where at least I believe it deserves to be. That's because of a number of reasons. Let's sum it up by saying that Relay isn't as accessible to get started with as the alternatives, and not as easy to find good learning material on. This meetup is a first step towards helping tackling that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Helping to grow the community
&lt;/h2&gt;

&lt;p&gt;I've been involved with the Relay community for a long time now. In addition to using Relay both professionally and personally since it was released, I've built a &lt;a href="https://github.com/zth?tab=repositories&amp;amp;q=relay&amp;amp;type=source"&gt;bunch of projects and experiments related to Relay&lt;/a&gt;, written a number of &lt;a href="https://dev.to/zth/relay-the-graphql-client-that-wants-to-do-the-dirty-work-for-you-55kd"&gt;articles on Relay&lt;/a&gt; and contributed some to Relay itself.&lt;/p&gt;

&lt;p&gt;I'm also a partner at the Swedish consultancy &lt;a href="https://arizon.se/consultancy"&gt;Arizon&lt;/a&gt;. We love Relay at Arizon, and we'd like to give back to the community somehow. This meetup is one way of doing that. Relay solves the problems we've been facing in UI development in a way that makes sense, is scalable, and intuitive. We'd love for more people to find their way to Relay, and experience what we've experienced.&lt;/p&gt;

&lt;h2&gt;
  
  
  21st of October - our first meetup
&lt;/h2&gt;

&lt;p&gt;Our first meetup will be held at the 21st of October at 19:00 GMT+2 (&lt;a href="https://www.thetimezoneconverter.com/?t=19%3A00&amp;amp;tz=Stockholm"&gt;check your timezone here&lt;/a&gt;), streamed on YouTube (&lt;a href="https://www.youtube.com/channel/UCxj4aSkoqMQ_aLTo-lieGOQ"&gt;subscribe to the channel here&lt;/a&gt;), and available for anyone to watch both live and afterwards.&lt;/p&gt;

&lt;p&gt;Here's what we'll cover in this first meetup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Relay in production
&lt;/h3&gt;

&lt;p&gt;The first meetup will feature &lt;a href="https://twitter.com/alloy"&gt;Eloy Durán&lt;/a&gt;, former Director of Engineering at &lt;a href="https://www.artsy.net"&gt;Artsy&lt;/a&gt;. Artsy has been using Relay for a long time, and we'll talk about Eloy's and Artsy's experience of using Relay in production over the years.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating the cache after mutations
&lt;/h3&gt;

&lt;p&gt;Our theme for the evening is &lt;em&gt;updating the cache after mutations&lt;/em&gt;. We'll dive into strategies for updating the cache after mutations in simple as well as more complex scenarios. &lt;/p&gt;

&lt;p&gt;This segment will feature &lt;a href="https://www.twitter.com/kassens"&gt;Jan Kassens&lt;/a&gt; from the Relay core team at Facebook, as well as Eloy again. Together we'll discuss various approaches for updating the cache, as well as how both Facebook and Artsy, two very different applications with different needs, approach these problems.&lt;/p&gt;

&lt;p&gt;Check out the event on &lt;a href="https://relaymeetup.com/meetups/1"&gt;our website here&lt;/a&gt;, the scheduled &lt;a href="https://www.youtube.com/watch?v=jdFVc28G_-A"&gt;YouTube stream here&lt;/a&gt;, and the &lt;a href="https://www.meetup.com/relay-meetup/events/273730799/"&gt;Meetup.com event here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get involved!
&lt;/h2&gt;

&lt;p&gt;Again, I'm very excited to finally be able to do something like this in the Relay community. Relay is a passion of mine, and I fully believe that the value of Relay now, with suspense and concurrent mode incoming, is greater than ever. There hasn't been a better and more exciting time to get into Relay.&lt;/p&gt;

&lt;p&gt;Please don't hesitate to reach out if you're interested in getting involved. Here's a few things we'd love to see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There's a lot of businesses and people using Relay outside of Facebook, and we'd like to involve the industry as much as possible. Is your company using Relay? Come on the meetup and talk about your experience!&lt;/li&gt;
&lt;li&gt;Have something interesting around Relay to present? Or have a cool demo of something related to Relay you'd like to show? Have a vague feeling that you have something interesting to show or tell, but don't know just how yet? Reach out to us and we'll figure it out together!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, if you want to stay current with what we're up to, don't forget to &lt;a href="https://twitter.com/relaymeetup"&gt;follow us on Twitter&lt;/a&gt; and &lt;a href="https://www.meetup.com/relay-meetup/"&gt;join our Meetup.com group&lt;/a&gt; if you're on there.&lt;/p&gt;

&lt;p&gt;Looking forward to seeing you the 21st of October for a fun evening full of interesting content on Relay!&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>javascript</category>
      <category>react</category>
      <category>relay</category>
    </item>
    <item>
      <title>The magic of the Node interface</title>
      <dc:creator>Gabriel Nordeborn</dc:creator>
      <pubDate>Thu, 16 Apr 2020 20:46:17 +0000</pubDate>
      <link>https://forem.com/zth/the-magic-of-the-node-interface-4le1</link>
      <guid>https://forem.com/zth/the-magic-of-the-node-interface-4le1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This series of articles is written by &lt;a href="https://github.com/zth"&gt;Gabriel Nordeborn&lt;/a&gt; and &lt;a href="https://github.com/sgrove"&gt;Sean Grove&lt;/a&gt;. Gabriel is a frontend developer and partner at the Swedish IT consultancy &lt;a href="https://arizon.se"&gt;Arizon&lt;/a&gt;, and has been a Relay user for a long time. Sean is a co-founder of &lt;a href="https://www.onegraph.com"&gt;OneGraph.com&lt;/a&gt;, unifying 3rd-party APIs with GraphQL.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The official GraphQL website recently added a section called &lt;a href="https://graphql.org/learn/global-object-identification/"&gt;“Global Object Identification” to its collection of best practices&lt;/a&gt;. In this article, we’ll dive into what global object identification is, why it’s useful and what type of developer experience it enables.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Global Object Identification?
&lt;/h2&gt;

&lt;p&gt;Global Object Identification in GraphQL is about two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Having each individual object in the graph be identifiable by a globally unique ID, &lt;em&gt;across types&lt;/em&gt;. So no two objects can have the same ID, even if they're of different types.&lt;/li&gt;
&lt;li&gt;Being able to query &lt;em&gt;any single object that has an&lt;/em&gt; &lt;code&gt;id&lt;/code&gt; only by that &lt;code&gt;id&lt;/code&gt;. This is done via the &lt;code&gt;Node&lt;/code&gt; interface which we’ll talk more in depth about below.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This enables libraries to safely automated away several things that are otherwise left up to the developer to implement and manage themselves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A GraphQL framework can automatically update the cache of any object since all objects have a unique ID.&lt;/li&gt;
&lt;li&gt;If we ever need to fetch &lt;em&gt;new&lt;/em&gt; or &lt;em&gt;refreshed&lt;/em&gt; fields on an object, all we need to know is its &lt;code&gt;GraphQL type&lt;/code&gt; and its &lt;code&gt;id&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll go deeper into why these two points enable a great developer experience below. &lt;/p&gt;

&lt;h2&gt;
  
  
  What’s the &lt;code&gt;Node&lt;/code&gt; interface anyway?
&lt;/h2&gt;

&lt;p&gt;In schemas implementing the &lt;code&gt;Node&lt;/code&gt; interface, you’ll see a top level field on the &lt;code&gt;Query&lt;/code&gt; object called &lt;code&gt;node&lt;/code&gt;, and it takes a single argument: &lt;code&gt;id&lt;/code&gt;, and it returns a single field: &lt;code&gt;id&lt;/code&gt; .&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Wat?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When you first look at it, it’s indeed a bit strange!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NodeInterfaceExample1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;gitHub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MDQ6VXNlcjM1Mjk2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# As one might expect, this is indeed "MDQ6VXNlcjM1Mjk2"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But because &lt;code&gt;node&lt;/code&gt; is an &lt;em&gt;interface&lt;/em&gt;, it implements every GraphQL object in the schema that can be fetched via its &lt;code&gt;id&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NodeInterfaceExample2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;gitHub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MDQ6VXNlcjM1Mjk2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GitHubUser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# "sgrove"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;followers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;totalCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# it's over 9000!!!!&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  But why is it useful?
&lt;/h2&gt;

&lt;p&gt;That means that if we know the &lt;em&gt;id&lt;/em&gt; and the &lt;em&gt;GraphQL Type&lt;/em&gt; of a thing, then we &lt;em&gt;always&lt;/em&gt; know how to look it up. The alternative might be something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WithoutInterfaceExample&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;gitHub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sgrove"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;followers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;totalCount&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There are two challenges with this query that will mean lots of extra work for us as developers, but that means extra chances for us to get things wrong:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Finding a &lt;code&gt;GitHubUser&lt;/code&gt; this way doesn’t accept its &lt;code&gt;id&lt;/code&gt;, it only accepts a &lt;code&gt;login&lt;/code&gt; argument. That means if we ever had, say, an &lt;code&gt;ownerId&lt;/code&gt; value, we still need to know the &lt;code&gt;*login*&lt;/code&gt; value. This gets trickier and trickier because every kind of object might be looked up by different keys.&lt;/li&gt;
&lt;li&gt;Even if we &lt;em&gt;had&lt;/em&gt; the &lt;code&gt;login&lt;/code&gt; value, we have to build a potentially complicated query with nested selections (&lt;code&gt;gitHub.user&lt;/code&gt; in this case) to get the extra fields we want.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ultimately, both those bits of knowledge are implicit - we know them as developers, we have that knowledge in our head - and that means the computer and our tooling doesn’t know it.&lt;/p&gt;

&lt;p&gt;But if our tooling &lt;em&gt;does&lt;/em&gt; know how to look up any object given its &lt;code&gt;id&lt;/code&gt;, then it can help us in wonderful ways. &lt;/p&gt;

&lt;p&gt;This will also relieve some pressure on the backend. Whenever you need to refetch a node that’s deeply nested in a query, the backend will need to resolve all levels above the node in order to get to it. If it’s able to just take the &lt;code&gt;id&lt;/code&gt; and resolve a single node directly though, that added pressure goes away.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why globally unique ids? Aren’t integers good enough?
&lt;/h1&gt;

&lt;p&gt;So with the &lt;code&gt;node&lt;/code&gt; interface we can look up &lt;em&gt;any&lt;/em&gt; object by its &lt;code&gt;id&lt;/code&gt; - great! But that comes with an implication: No two objects in our entire API can have the same id!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Quick aside: This &lt;em&gt;seems&lt;/em&gt; daunting for just a moment at first, but there's an easy way to do this for any schema that we’ll see in just a moment&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That means that every GraphQL object that has an &lt;code&gt;id&lt;/code&gt; field (say, &lt;code&gt;User.id&lt;/code&gt; or &lt;code&gt;Post.id&lt;/code&gt;) must have a unique ID that &lt;em&gt;no other GraphQL Object has&lt;/em&gt;. Take this query for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FirstUserAndFirstPost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It’s common for lots of databases to use incrementing integers as ids, so you might expect a response like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"post"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But combined with the &lt;code&gt;node&lt;/code&gt; interface, this just won’t work. Say we have a post id and we want to get some additional fields (like its &lt;code&gt;title&lt;/code&gt;). We &lt;em&gt;should&lt;/em&gt; be able to run this query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NodeInterfaceExample3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But there are &lt;em&gt;two&lt;/em&gt; objects that could be looked up with the &lt;code&gt;id&lt;/code&gt; of &lt;code&gt;1&lt;/code&gt;! It’s now unclear if the object that will come back will be a &lt;code&gt;User&lt;/code&gt; or a &lt;code&gt;Post&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don’t lose heart! A simple solution is at hand!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So if we want to &lt;em&gt;internally&lt;/em&gt; keep using integers for our ID, how can we have globally unique IDs? Let’s look at the example ID used in the GitHub (whose API is beautiful and Relay compatible as well!) query: &lt;code&gt;node(id: "MDQ6VXNlcjM1Mjk2")&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;gt; atob("MDQ6VXNlcjM1Mjk2")
    "04:User35296"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Hey, I see some integers in there!&lt;/p&gt;

&lt;p&gt;Basically, the technique is to construct a &lt;code&gt;nodeId&lt;/code&gt;, and it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="s2"&gt;`base64Encode(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;GraphQLObjectTypeName&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So for our &lt;code&gt;post&lt;/code&gt; and our &lt;code&gt;user&lt;/code&gt; on version 1 of our API, we would expect to see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    "MDE6UG9zdDE=" # decodes to "01:Post1"
    "MDE6VXNlcjE=" # decodes to "01:User1"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If we revisit our previous node example that had a conflict and use our new ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NodeInterfaceExample4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MDE6UG9zdDE="&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now our single &lt;code&gt;node&lt;/code&gt; resolver can base64-decode the id, find that it’s looking for a &lt;code&gt;Post&lt;/code&gt; object with &lt;code&gt;id&lt;/code&gt; of &lt;code&gt;1&lt;/code&gt;, and return the correct object.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The reason we prefix the API version in the global id is to give us a chance to later change how we encode global ids in a non-breaking way, in case we need it. It’s a bit of flexibility we can buy for effectively nothing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If things aren't quite clicking for you yet (especially if you don't get &lt;em&gt;why&lt;/em&gt; an &lt;code&gt;id&lt;/code&gt; would be anything but the database id of that object), it might help to think of the &lt;code&gt;id&lt;/code&gt; field on a GraphQL type this way - you’re actually looking at a node in &lt;em&gt;GraphQL&lt;/em&gt;, an entire graph, and not in your database table. This means that when you’re looking at the &lt;code&gt;id&lt;/code&gt; of a GraphQL type, you’re looking at a node in a graph, not a table in a database. In this light, having the &lt;code&gt;id&lt;/code&gt; of a GraphQL type be globally unique makes much more sense, since its primary objective is to be an identifier in your graph of objects, not in your database.&lt;/p&gt;

&lt;h1&gt;
  
  
  What does this enable?
&lt;/h1&gt;

&lt;p&gt;Like demonstrated above, most schemas will already have &lt;em&gt;some&lt;/em&gt; way of resolving a single item of most things, even if it’s not via a top level &lt;code&gt;node&lt;/code&gt; field. So why does this whole thing matter? Is it just for making the resolution slightly more convenient?&lt;/p&gt;

&lt;p&gt;Well, that helps too of course. But the real power comes from &lt;em&gt;standardization&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;If you think about it, even if your schema has a top level field called &lt;code&gt;postById(id: ID!)&lt;/code&gt;, that indeed does resolve a post by an ID, there’s really no way for anyone but the schema creator to know that’s in fact what the field does. Without parsing the semantical meaning of &lt;code&gt;postById&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; inferring that it in fact does mean “a single post, just by its ID”, any external tooling or framework will not be able to safely assume that that’s what that particular field does. You may have any number of fields resolving a single &lt;code&gt;Post&lt;/code&gt;, like &lt;code&gt;postByDatabaseId(id: ID!): Post&lt;/code&gt;, &lt;code&gt;mostLikedPost(id: ID!): Post&lt;/code&gt;, &lt;code&gt;latestPost(id: ID!): Post&lt;/code&gt; and so on. This makes it impossible for external tooling to safely assume which field it can use to refetch a single &lt;code&gt;Post&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Node&lt;/code&gt; interface, however, is an &lt;a href="https://graphql.org/learn/global-object-identification/"&gt;official GraphQL best practice&lt;/a&gt;, and this means that frameworks and tooling can build on top of it and anyone who implements it will benefit. And there’s some pretty cool things you can build with it. Let’s look at some concrete examples from Relay:&lt;/p&gt;

&lt;h2&gt;
  
  
  Autogeneration of pagination queries
&lt;/h2&gt;

&lt;p&gt;The latest iteration of Relay (now called only Relay, but commonly referred to as Relay Modern) can automatically generate queries for refetching or paginating data, since it can refetch any GraphQL object via the &lt;code&gt;Node&lt;/code&gt; interface. This is enables a very ergonomic developer experience. Basically, Relay can take something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fragment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserFriendsList_user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;friends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$after&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And automatically generate a pagination query for that, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserFriendsListPaginationQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;!,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;friends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$after&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;…just because it knows that &lt;code&gt;User&lt;/code&gt;, the type the fragment &lt;code&gt;UserFriendsList_user&lt;/code&gt; is on and where the pagination is defined, implements the &lt;code&gt;node&lt;/code&gt; interface, and can therefore be &lt;em&gt;re-fetched&lt;/em&gt; via its &lt;code&gt;id&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;It doesn’t matter &lt;em&gt;where&lt;/em&gt; the &lt;code&gt;User&lt;/code&gt; whose friends we’re paginating is located in the query, the &lt;code&gt;node&lt;/code&gt; interface let Relay refetch &lt;em&gt;any&lt;/em&gt; &lt;code&gt;User&lt;/code&gt;as long as it has its &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We have a whole &lt;a href="https://dev.to/zth/pagination-with-minimal-effort-in-relay-gl4"&gt;article on pagination in Relay&lt;/a&gt; you’re encouraged to check out here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Autogeneration of queries for your typical "Show more" functionality
&lt;/h2&gt;

&lt;p&gt;In the same vein, Relay makes it really easy to build a classic "Show more" functionality. Relay can help you take something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fragment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ProfilePage_user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;avatarUrl&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;bio&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;@include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;if&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$showMore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;...and generate a query that'll let you fetch that fragment again, but now including &lt;code&gt;bio&lt;/code&gt; by setting &lt;code&gt;$showMore&lt;/code&gt; to true. &lt;/p&gt;

&lt;p&gt;Your experience of building the "show more" functionality would basically be as simple as running &lt;code&gt;refetch({showMore: true})&lt;/code&gt; when the user presses the "Show more"-button. Relay takes care of the rest, and it can do that &lt;em&gt;because&lt;/em&gt; it knows how to refetch that &lt;code&gt;User&lt;/code&gt; via its &lt;code&gt;id&lt;/code&gt; using the &lt;code&gt;Node&lt;/code&gt; interface, regardless of where that &lt;code&gt;User&lt;/code&gt; is found.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Hopefully you’ve now got some insight into why globally unique IDs and the &lt;code&gt;Node&lt;/code&gt; interface is a good idea. Relay make great use of it, and since it’s an official GraphQL best practice, any other tooling can build on top of it too.&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>relay</category>
    </item>
    <item>
      <title>Pagination with minimal effort in Relay</title>
      <dc:creator>Gabriel Nordeborn</dc:creator>
      <pubDate>Thu, 16 Apr 2020 20:46:09 +0000</pubDate>
      <link>https://forem.com/zth/pagination-with-minimal-effort-in-relay-gl4</link>
      <guid>https://forem.com/zth/pagination-with-minimal-effort-in-relay-gl4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This series of articles is written by &lt;a href="https://github.com/zth"&gt;Gabriel Nordeborn&lt;/a&gt; and &lt;a href="https://github.com/sgrove"&gt;Sean Grove&lt;/a&gt;. Gabriel is a frontend developer and partner at the Swedish IT consultancy &lt;a href="https://arizon.se"&gt;Arizon&lt;/a&gt;, and has been a Relay user for a long time. Sean is a co-founder of &lt;a href="https://www.onegraph.com"&gt;OneGraph.com&lt;/a&gt;, unifying 3rd-party APIs with GraphQL.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pagination. Everyone gets there eventually, and - let’s be honest - it’s not fun. In this article we’ll show that when you follow a few conventions, pagination in Relay may not be &lt;em&gt;fun&lt;/em&gt;, but it &lt;em&gt;is&lt;/em&gt; easy and ergonomic. &lt;/p&gt;

&lt;p&gt;This article will focus on simple pagination, without filters, and only paginating forward. But, Relay can paginate backwards just as easily, and handles the filter case beautifully. You can read more about &lt;a href="https://relay.dev/docs/en/experimental/a-guided-tour-of-relay#rendering-list-data-and-pagination"&gt;those two things here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, for pagination in Relay to be as sweet as it can, your GraphQL server will need to follow two specific GraphQL best practices:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://graphql.org/learn/global-object-identification/"&gt;Global object identification and the &lt;code&gt;Node&lt;/code&gt; interface&lt;/a&gt;. We also have another article about that you can &lt;a href="https://dev.to/zth/the-magic-of-the-node-interface-4le1"&gt;read here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://graphql.org/learn/pagination/"&gt;Connection based pagination&lt;/a&gt;. Again, we have a separate article you're much welcome &lt;a href="https://dev.to/zth/connection-based-pagination-in-graphql-2588"&gt;to read here&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this article, we’ll lay out a familiar example app first, and then walk through the challenges in implementing the required pagination. Finally, we’ll illustrate Relay’s solution to said problems.&lt;/p&gt;

&lt;h1&gt;
  
  
  How is pagination typically done in GraphQL clients?
&lt;/h1&gt;

&lt;p&gt;Pagination usually consists of this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You fetch some form of initial list of items, usually through another query (typically the main query for the view you’re in). This query normally contains a bunch of other things in addition to items from the list you want to paginate.&lt;/li&gt;
&lt;li&gt;You define a &lt;em&gt;separate&lt;/em&gt; query that can fetch &lt;em&gt;more&lt;/em&gt; items for the list.&lt;/li&gt;
&lt;li&gt;You use the &lt;em&gt;separate&lt;/em&gt; query with the appropriate cursor that you got from the &lt;em&gt;first&lt;/em&gt; query in order to paginate forward, specifying the number of items you want&lt;/li&gt;
&lt;li&gt;Then you write code to merge the items from the &lt;em&gt;first&lt;/em&gt; list with the new items, and re-render your view&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s see that in action now, with a typical example that gets all the data for a user’s profile page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ProfileQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$userLogin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;gitHub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$userLogin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;avatarUrl&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;following&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;totalCount&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;followers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;totalCount&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="n"&gt;avatarUrl&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Our query pulls out two groups of data we care about:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Profile information for our user, like name and email&lt;/li&gt;
&lt;li&gt;A list of followers with some fields for each one. To start with, we just get the first 5 followers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now that we have our first query, let’s paginate to get the next 5 followers (we have some popular users!).&lt;/p&gt;

&lt;h2&gt;
  
  
  Trying to re-use the original query isn't good enough
&lt;/h2&gt;

&lt;p&gt;The first thing we notice is that we probably shouldn't reuse the first query we defined for pagination. We’ll need a new query, because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We don’t want to fetch all of the profile information for the user again, since we already have it and fetching it again might be expensive.&lt;/li&gt;
&lt;li&gt;We know we want to start off with only the first 5 followers and delegate loading more to actual pagination, so adding variables for pagination in this initial query feels redundant and would add unnecessary complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, let’s write the new query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserProfileFollowersPaginationQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nv"&gt;$userLogin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!,&lt;/span&gt;&lt;span class="w"&gt; 
      &lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;!,&lt;/span&gt;&lt;span class="w"&gt; 
      &lt;/span&gt;&lt;span class="nv"&gt;$after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;gitHub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$userLogin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;followers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$after&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;pageInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;hasNextPage&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;endCursor&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="n"&gt;avatarUrl&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here we go! We now have all we need to paginate. Great! But, there’s a few things to note here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We need to write this query by hand&lt;/li&gt;
&lt;li&gt;Even though we know what &lt;code&gt;User&lt;/code&gt; we want to paginate followers on already, we need to give the query that information again through variables. This also needs to &lt;em&gt;exactly match&lt;/em&gt; how our initial query is selecting the user, so we're getting the right one&lt;/li&gt;
&lt;li&gt;We’ll need to manually give the query the next cursor to paginate from. Since this will always be the end cursor in this view, this is just manual labor that needs to be done&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s a shame that we need to do all of this manual work. What if the framework could just generate this pagination query for us, and maybe deal with all the steps that will always be the same anyway…? &lt;/p&gt;

&lt;p&gt;Well, using the &lt;code&gt;node&lt;/code&gt; interface and connection based pagination, Relay can!&lt;/p&gt;

&lt;h2&gt;
  
  
  Pagination in Relay
&lt;/h2&gt;

&lt;p&gt;Let’s illustrate how pagination works in Relay with a similar example to the one above - a simple profile page. The profile page lists some information about the user, and then also list the users friends. The list of friends should be possible to paginate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// Profile.ts&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useLazyLoadQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-relay/hooks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;graphql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-relay&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ProfileQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./__generated__/ProfileQuery.graphql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FriendsList&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./FriendsList&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;userById&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useLazyLoadQuery&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ProfileQuery&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="s2"&gt;`
          query ProfileQuery($userId: ID!) {
            userById(id: $userId) {
              firstName
              lastName
              ...FriendsList_user
            }
          }
        `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;userById&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userById&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userById&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Friends&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FriendsList&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userById&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here’s our root component for showing the profile page. As you can see it makes a query, asks for some information that it’s displaying itself (&lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt;), and then includes the &lt;code&gt;FriendsList_user&lt;/code&gt; fragment, which contains the data the &lt;code&gt;FriendsList&lt;/code&gt; component need on the &lt;code&gt;User&lt;/code&gt; type to be able to render. &lt;/p&gt;

&lt;h2&gt;
  
  
  The power of true modularity of components
&lt;/h2&gt;

&lt;p&gt;No pagination to be seen anywhere so far though, right? Hold on, it’s coming! But, first, notice this: &lt;em&gt;This component doesn’t need to know&lt;/em&gt; that &lt;code&gt;&amp;lt;FriendsList /&amp;gt;&lt;/code&gt; is doing pagination. That is another strength of Relay. Let’s highlight a few implications this has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Any component can introduce pagination &lt;em&gt;in isolation&lt;/em&gt; without needing any action from components that already render it. Thinking “meh”? You won't when you have a component spread out through a fairly large number of screens that you need to introduce pagination to without it being a 2 week project.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ProfileQuery&lt;/code&gt; doesn’t need to define anything unnecessary, like variables, just to ensure that &lt;code&gt;&amp;lt;FriendsList /&amp;gt;&lt;/code&gt;  can paginate.&lt;/li&gt;
&lt;li&gt;Alluding to the points above, this means that no implicit (or explicit) dependencies are created between components, which in turn means that you can safely refactor and maintain your components without risking breaking stuff. It also means you can do said things &lt;em&gt;fast&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building the component that does the pagination
&lt;/h2&gt;

&lt;p&gt;Below is the &lt;code&gt;FriendsList&lt;/code&gt; component, which is what’s actually doing the pagination. This is a bit more dense:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// FriendsList.ts&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;usePaginationFragment&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-relay/hooks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;graphql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-relay&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FriendsList_user$key&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./__generated__/FriendsList_user_graphql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FriendsListPaginationQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./__generated__/FriendsListPaginationQuery_graphql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getConnectionNodes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./utils/getConnectionNodes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FriendsList_user$key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FriendsList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hasNext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loadNext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoadingNext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;usePaginationFragment&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
        &lt;span class="nx"&gt;FriendsListPaginationQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;_&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="s2"&gt;`
          fragment FriendsList_user on User
            @argumentDefinitions(
              first: { type: "Int!", defaultValue: 5 }
              after: { type: "String" }
            )
            @refetchable(queryName: "FriendsListPaginationQuery") {
            friends(first: $first, after: $after)
              @connection(key: "FriendsList_user_friends") {
              edges {
                node {
                  id
                  firstName
                }
              }
            }
          }
        `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;user&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;getConnectionNodes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;friends&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;friend&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;friend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;friend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;))}&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hasNext&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
              &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoadingNext&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;loadNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoadingNext&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Load more&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There’s a lot going on here, and we will break it all down momentarily, but notice how little manual work we’ve needed to do. Here’s a few things to note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No need to define a custom query to use for paginating. It’s automatically generated for us by Relay.&lt;/li&gt;
&lt;li&gt;No need to keep track of what’s the next cursor to paginate from. Relay does it for us, so we can’t mess that up.&lt;/li&gt;
&lt;li&gt;No need for any custom logic for merging the pagination results with what’s already in the store. Relay does it for us.&lt;/li&gt;
&lt;li&gt;No need to do anything extra to keep track of the loading state or if there are more items I can load. Relay supplies us with that with no additional action needed from our side.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other than the benefit that less code is nice just by itself, there’s also the benefit of less hand rolled code meaning less things to potentially mess up.&lt;/p&gt;

&lt;p&gt;Let’s break down everything in the code snippet above that make that possible, because there’s likely a few things in there making you scratch your head:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FriendsList_user$key&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./__generated__/FriendsList_user_graphql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FriendsListPaginationQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./__generated__/FriendsListPaginationQuery_graphql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;At the top we’re importing a bunch of type definitions from a &lt;code&gt;__generated__&lt;/code&gt; folder. These are to ensure type safety for both for the fragment we’re defining and the for pagination query that is automatically generated for us by the Relay compiler for each GraphQL operation we define in our project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getConnectionNodes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./utils/getConnectionNodes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We also import a function called &lt;code&gt;getConnectionNodes&lt;/code&gt;. This is a custom helper that can extract all nodes from any connection into an array in a type safe way. It’s not from the official Relay packages, but it’s very easy to make one yourself, as you can see an &lt;a href="https://github.com/zth/relay-utils/blob/master/src/collectConnectionNodes.js"&gt;example of here&lt;/a&gt;. It’s a great example of the type of tooling you can build easily because of standardization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hasNext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loadNext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoadingNext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;usePaginationFragment&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
        &lt;span class="nx"&gt;FriendsListPaginationQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;_&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="s2"&gt;`
          fragment FriendsList_user on User
            @argumentDefinitions(
              first: { type: "Int!", defaultValue: 5 }
              after: { type: "String" }
            )
            @refetchable(queryName: "FriendsListPaginationQuery") {
            friends(first: $first, after: $after)
              @connection(key: "FriendsList_user_friends") {
              edges {
                node {
                  id
                  firstName
                }
              }
            }
          }
        `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;user&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We use a hook called &lt;code&gt;usePaginationFragment&lt;/code&gt; which gives us back a bunch of props related to pagination. It also gives us &lt;code&gt;data&lt;/code&gt;, which is the data for the &lt;code&gt;FriendsList_user&lt;/code&gt; fragment we’re defining.&lt;/p&gt;

&lt;p&gt;Speaking of the fragment, that’s where most of the good stuff is happening. Let’s go deeper into what’s going on in the fragment definition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="err"&gt;@argumentDefinitions(&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="err"&gt;first:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="err"&gt;after:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Relay let you define arguments for fragments
&lt;/h2&gt;

&lt;p&gt;The first thing that stands out is that we’ve added a directive to the fragment called &lt;code&gt;@argumentDefinitions&lt;/code&gt;, which define two arguments, &lt;code&gt;first&lt;/code&gt; (as &lt;code&gt;Int!&lt;/code&gt;) and &lt;code&gt;after&lt;/code&gt; (as &lt;code&gt;String&lt;/code&gt;). &lt;code&gt;first&lt;/code&gt; is required, so if no argument is given to the fragment for that, Relay will use the defined default value, which in this case is &lt;code&gt;5&lt;/code&gt;. This is how Relay knows to fetch the first 5 followers in &lt;code&gt;ProfileQuery&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The ability to define arguments for fragments is another feature of Relay that make all the difference for modularity and scalability. We won’t go deeper into exactly how this works, but this would allow any user of the &lt;code&gt;FriendsList_user&lt;/code&gt; fragment to override the values of &lt;code&gt;first&lt;/code&gt; and &lt;code&gt;after&lt;/code&gt; when using that fragment. Like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SomeUserQuery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;loggedInUser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="n"&gt;FriendsList_user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;@arguments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This would fetch the first 10 followers directly in &lt;code&gt;&amp;lt;FriendsList /&amp;gt;&lt;/code&gt; instead of just the first 5, which is the default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Relay writes your pagination query for you
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="err"&gt;@refetchable(queryName:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"FriendsListPaginationQuery")&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After that comes another directive, &lt;code&gt;@refetchable&lt;/code&gt;. This is telling Relay that you want to be able to refetch the fragment with new variables, and &lt;code&gt;queryName&lt;/code&gt; that’s provided to the directive says that &lt;code&gt;FriendsListPaginationQuery&lt;/code&gt; is what you want the generated query to be called.&lt;/p&gt;

&lt;p&gt;This would generate a query that looks &lt;em&gt;roughly&lt;/em&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FriendsListPaginationQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;!,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;friends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$after&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;pageInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;endCursor&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;hasNextPage&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;startCursor&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;hasPreviousPage&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;But you don’t need to know, think or care about this!&lt;/strong&gt; Relay will take care of &lt;em&gt;all the plumbing&lt;/em&gt; for you, like supplying all needed variables for the query (like &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;after&lt;/code&gt;, which is the cursor to paginate from next). You only need to say how many more items you want to fetch.&lt;/p&gt;

&lt;p&gt;This is the meat of what makes pagination so ergonomic with Relay - Relay will literally &lt;em&gt;write your code and queries for you&lt;/em&gt;, hiding all of that complexity of pagination for you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Let Relay know where it can find your connection, and it’ll do the rest
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="err"&gt;friends(first:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;after:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$after)&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="err"&gt;@connection(key:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"FriendsList_user_friends")&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;**friends(first: $first, after: $after)**&lt;/code&gt;&lt;br&gt;
After that comes the field selection. &lt;code&gt;friends&lt;/code&gt; is the field with the connection we want to paginate. Notice that we’re passing that the &lt;code&gt;first&lt;/code&gt; and &lt;code&gt;after&lt;/code&gt; arguments defined in &lt;code&gt;@argumentDefinitions&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;**@connection**&lt;/code&gt;&lt;br&gt;
Attached to &lt;code&gt;friends&lt;/code&gt; is another directive, &lt;code&gt;@connection(key:&lt;/code&gt; &lt;code&gt;"&lt;/code&gt;&lt;code&gt;FriendsList_user_friends&lt;/code&gt;&lt;code&gt;"&lt;/code&gt;&lt;code&gt;)&lt;/code&gt;. This directive tell Relay that here’s the location of the connection you want to paginate. Adding this allow Relay to do a few things, like automatically add the full selection for &lt;code&gt;pageInfo&lt;/code&gt; on the connection selection in the query that’s sent to the server. Relay then uses that information both to tell you whether you can load more, and to automatically use the appropriate cursor for paginating. Again, removing manual steps that can go wrong and automating them.&lt;/p&gt;

&lt;p&gt;Again, you don’t need to see or think about this as Relay takes care of all of this, but the actual selection on &lt;code&gt;friends&lt;/code&gt; that’s sent to the server look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;friends(first:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;after:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$after)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;pageInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;endCursor&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;hasNextPage&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;startCursor&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;hasPreviousPage&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;egdes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;      
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By adding the &lt;code&gt;@connection&lt;/code&gt; annotation, Relay knows where to add the selections it needs to know how to paginate.&lt;/p&gt;

&lt;p&gt;The next thing &lt;code&gt;@connection&lt;/code&gt; does is tell Relay what &lt;code&gt;key&lt;/code&gt; you want to use if you need to interact with this connection in the cache, like when adding or removing items to the connection through cache updates. Setting a unique &lt;code&gt;key&lt;/code&gt; here is important because you may have multiple lists paginating over the same connection at the same time.&lt;/p&gt;

&lt;p&gt;It also means that Relay can infer the location of everything it needs to extract from the pagination response and add to the current pagination list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
              &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoadingNext&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;loadNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Other than that, most of the code that actually use the things Relay give us should be fairly self explanatory. &lt;/p&gt;

&lt;h2&gt;
  
  
  How can this work?
&lt;/h2&gt;

&lt;p&gt;So, summing up what pagination looks like, you’re basically giving Relay the information it needs through directives in your fragment definition, and in return Relay automates everything it can for you.&lt;/p&gt;

&lt;p&gt;But, how can Relay do all of this? &lt;/p&gt;

&lt;p&gt;It all boils down to conventions and standardization. If you follow the &lt;a href="https://graphql.org/learn/global-object-identification/"&gt;global identification and &lt;code&gt;node&lt;/code&gt; interface specification&lt;/a&gt;, Relay can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically generate a query to refetch the particular node we’re on, and automatically add the fragment we’re refetching to that query&lt;/li&gt;
&lt;li&gt;Ensure you won’t need to supply any variables for the generated query at all, since it knows that the &lt;code&gt;id&lt;/code&gt; for the object we’re looking at can only lead to that particular object&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And, by following the &lt;a href="https://graphql.org/learn/pagination/"&gt;connection specification for pagination&lt;/a&gt;, Relay can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically add whatever metadata selection it needs to the queries, both the initial &lt;code&gt;ProfileQuery&lt;/code&gt; and the generated &lt;code&gt;FriendsListPaginationQuery&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Automatically merge the pagination results with the existing list, since it knows that the structure of the data is a standardized connection, and therefore it can extract whatever it needs&lt;/li&gt;
&lt;li&gt;Automatically keep track of what cursor to use for loading more results, since that will be available on &lt;code&gt;pageInfo&lt;/code&gt; in a standardized way. &lt;code&gt;pageInfo&lt;/code&gt; which it (as mentioned above) can automatically insert into the query selection without you knowing about it. Again because it’s standardized.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the result is really sweet. In addition to making pagination much more ergonomic, Relay has also eliminated just about every surface for manual errors we’d otherwise have.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;In this article, we’ve tried to highlight just how much a framework like Relay can automate for you, and how incredible the DX can be, if you follow conventions. This article has tried to shed some light on the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pagination in GraphQL can require a lot of manual work and offer lots of surface for messing up as a developer&lt;/li&gt;
&lt;li&gt;By following conventions, a framework like Relay can turn the pagination experience into something incredibly ergonomic and remove most (if not &lt;em&gt;all&lt;/em&gt;) surfaces for manual errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While this is a good primer, there are many more features and capabilities for pagination in Relay that we can explore. You can read all about that in Relay’s official documentation &lt;a href="https://relay.dev/docs/en/experimental/a-guided-tour-of-relay#rendering-list-data-and-pagination"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>relay</category>
      <category>react</category>
    </item>
    <item>
      <title>Connection based pagination in GraphQL</title>
      <dc:creator>Gabriel Nordeborn</dc:creator>
      <pubDate>Thu, 16 Apr 2020 20:45:52 +0000</pubDate>
      <link>https://forem.com/zth/connection-based-pagination-in-graphql-2588</link>
      <guid>https://forem.com/zth/connection-based-pagination-in-graphql-2588</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This series of articles is written by &lt;a href="https://github.com/zth"&gt;Gabriel Nordeborn&lt;/a&gt; and &lt;a href="https://github.com/sgrove"&gt;Sean Grove&lt;/a&gt;. Gabriel is a frontend developer and partner at the Swedish IT consultancy &lt;a href="https://arizon.se"&gt;Arizon&lt;/a&gt;, and has been a Relay user for a long time. Sean is a co-founder of &lt;a href="https://www.onegraph.com"&gt;OneGraph.com&lt;/a&gt;, unifying 3rd-party APIs with GraphQL.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Connection based pagination is a way of structuring how you do pagination so it caters to both simple and a bit more advanced pagination. It was recently promoted to an &lt;a href="https://graphql.org/learn/pagination/"&gt;official GraphQL best practice&lt;/a&gt;, and this article will focus on why it’s a good thing in GraphQL, and what type of tooling it enables. &lt;/p&gt;

&lt;p&gt;There are numerous of resources about what connection based pagination is and why it’s useful. If you want to get your feet wet before reading this article, we recommend having a look at &lt;a href="https://graphql.org/learn/pagination/"&gt;the official GraphQL website&lt;/a&gt; section on pagination.&lt;/p&gt;

&lt;h3&gt;
  
  
  Standardization is the win
&lt;/h3&gt;

&lt;p&gt;Connection based pagination is all about using a standardized contract for pagination. Now, why would you care about that? Well, as we’ll show you throughout this article, a standardized contract means tooling and frameworks can integrate deeply with it. And that in turn means that your life as a developer will be a whole lot easier. It also means we can ship a lot faster, as our tooling will be doing some heavy lifting for us.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is it and what is it suitable for?
&lt;/h2&gt;

&lt;p&gt;Connection based pagination is best suited for infinite scroll type pagination, where you keep adding an arbitrary amount of items to an already existing list as you move through the UI. If you’re looking to implement pagination that fetches an entire page of items in isolation rather than continuously adding to an existing list, you’re better off implementing that separately.&lt;/p&gt;

&lt;p&gt;The key here is that connection based pagination is &lt;em&gt;just a way of structuring the contract for pagination&lt;/em&gt;. While there &lt;em&gt;may&lt;/em&gt; be implications for how you fetch your data backend when using connection based pagination, the primary purpose of using it in the GraphQL world is to provide a standardized structure for paginating, rather than committing your backend to a specific pagination strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  A standardized structure for pagination
&lt;/h2&gt;

&lt;p&gt;Now, let’s look at an example of the structure that connection based pagination follows. Imagine we’re building a search feature for finding movies we think you'll like. Our search backend is really smart, so we're able to factor in a bunch of things in our assessment of what we think you'd like to watch. The definition below symbolizes fetching and paginating a list of &lt;code&gt;Movie&lt;/code&gt; by an arbitrary search term. The search term could be something like &lt;code&gt;action movies&lt;/code&gt;, or &lt;code&gt;romcoms&lt;/code&gt;. Our search engine can make sense of it all! &lt;/p&gt;

&lt;p&gt;Feel free to skim through the spec - don’t spend time trying to understand it now. It’ll just be good to have the general shape in the back of your mind as you read the rest of the article.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Movie&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;releasedYear&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;coverUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="c"&gt;# An edge for the Movie type&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MovieEdge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Movie&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# The node, Movie in this case, for this edge&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# The cursor for this edge&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="c"&gt;# Metadata for the current pagination&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PageInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;hasNextPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;endCursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;hasPreviousPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;startCursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="c"&gt;# The connection, aka the root type of the pagination.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MovieConnection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;pageInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PageInfo&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MovieEdge&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="c"&gt;# first, last, after and before can be used to paginate forward and backward&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;movies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MovieConnection&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That’s a lot of structure for something that should be really simple, right? Like mentioned above, just keep the structure in the back of your head, and let’s look at a typical scenario of how pagination is implemented and how it can grow in a project.&lt;/p&gt;

&lt;h2&gt;
  
  
  A common scenario of how pagination is implemented
&lt;/h2&gt;

&lt;p&gt;Most applications need some form of pagination sooner or later, and it can be implemented in sorts of different ways. Let’s paint a scenario of how implementing the most common, run-of-the-mill pagination in GraphQL might look.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1. The “simplest possible pagination”
&lt;/h2&gt;

&lt;p&gt;Building on our movies example above, we’ll design a search function that can paginate movies by an arbitrary search query, like &lt;code&gt;the wild west&lt;/code&gt; or &lt;code&gt;intense action&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Most people (understandably!) start out basic: “We just want some very simple pagination, no need to be fancy”. It usually ends up looking something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;searchMovies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Movie&lt;/span&gt;&lt;span class="p"&gt;!]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We’re filtering a simple list of &lt;code&gt;Movie&lt;/code&gt; using a search query to find the the best matching movies for that search query. This is all fine and work well!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2. How do we know if there are more results?
&lt;/h2&gt;

&lt;p&gt;The product evolves, and we want to add a nice “See more movies”-button to our UI if there are more movies that can be fetched. But, since we’re just returning a list in the example above, we have no way of knowing whether there are more results to load or not.&lt;/p&gt;

&lt;p&gt;Well, we can solve this too quite easily! Let’s extend our example. We don’t want to modify an individual &lt;code&gt;Movie&lt;/code&gt; (it wouldn’t make sense to have a &lt;code&gt;hasNextPage&lt;/code&gt; property there), so we need &lt;code&gt;searchMovies&lt;/code&gt; to return a little wrapper object (&lt;code&gt;MovieSearchResult&lt;/code&gt; ) where we can put our metadata:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MovieSearchResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;hasNext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Movie&lt;/span&gt;&lt;span class="p"&gt;!]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;searchMovies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MovieSearchResult&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Great, this does everything we need. Problem solved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3. When using offset break down
&lt;/h2&gt;

&lt;p&gt;Our product evolves and we now need to make sure that we can produce a unique URL for continuing pagination from a specific &lt;code&gt;Movie&lt;/code&gt; in our results. &lt;/p&gt;

&lt;p&gt;The immediate reaction may be to build a URL like this:&lt;br&gt;
&lt;code&gt;/search?limit=${limit}&amp;amp;offset=${offset}&amp;amp;query=${query}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This should work, right? Sadly, not so well. &lt;/p&gt;

&lt;p&gt;What happens when movies are added to the database and would end up &lt;em&gt;before&lt;/em&gt; the movie we’re currently looking at in the results? The offset wouldn’t point to the movie we want. &lt;/p&gt;

&lt;p&gt;Let’s step back and express our intentions like human-beings talking to a backend API maintainer for a second:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I have all of the movie results up to “Frost 2”. I’d like to get the next 10 movies after Frost 2, please!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We’ve described enough of our intentions so that a human would know, “Oh, there have been a few other movies added and some removed that also match your search query, but here are the 10 after Frost 2 specifically.” &lt;em&gt;That’s&lt;/em&gt; the behavior we want in our pagination!&lt;/p&gt;

&lt;p&gt;For this to work, we’ll need to be able to paginate &lt;em&gt;from a specific item in the results&lt;/em&gt;. So naturally we’ll need a way of identifying a single item in the results. There’s a pre-existing concept for that called &lt;em&gt;cursors&lt;/em&gt; &lt;em&gt;-&lt;/em&gt; we’ll just use that concept (the best artist steal, and all that), and tweak our search query to support it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MovieSearchResultWrapper&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Movie&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MovieSearchResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;hasNext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MovieSearchResultWrapper&lt;/span&gt;&lt;span class="p"&gt;!]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;searchMovies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MovieSearchResult&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can now query movie's by a &lt;code&gt;cursor&lt;/code&gt; instead of just &lt;code&gt;offset&lt;/code&gt;, and we’ll have access to the &lt;code&gt;cursor&lt;/code&gt; for each result. This will ensure that our pagination is stable (items added before the current item won’t mess up the listing as before). We can now produce a URL like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/search?limit=${limit}&amp;amp;cursor=${cursor}&amp;amp;query=${query}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This URL will be stable, and always point to search results starting from the item in the results list (even if several have been added or removed in the meantime). Excellent!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4. Metadata relevant for each individual item in the search result
&lt;/h2&gt;

&lt;p&gt;A new feature request comes in - since we have all this fancy knowledge about how well we think each result both matches your &lt;em&gt;taste&lt;/em&gt; and how relevant it is to your &lt;em&gt;query&lt;/em&gt;, we naturally want to flex our muscles as show that to the user! &lt;/p&gt;

&lt;p&gt;However, this is data that's only really valid for a specific result item with a specific search query. Our search engine also automatically produces that information for us in an efficient way for each search result (since that's what it's already using to order the results). But, where would it be logical to put that information for each result if we don’t want to extend the root &lt;code&gt;Movie&lt;/code&gt; type (because that wouldn't really make sense)? Well, we just introduced  &lt;code&gt;MovieSearchResultWrapper&lt;/code&gt; for our cursor needs, and it happens to keep metadata only relevant to this particular search. Let’s put it there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MovieSearchResultWrapper&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Movie&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;relevanceFactor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Float&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Excellent, we now have a nice number we can turn into some fancy gauge meter and everyone will be happy!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait - didn’t we just implement connection based pagination organically?
&lt;/h2&gt;

&lt;p&gt;If you look at what we’ve produced organically here and compare it to the initial structure we drew up with connection based pagination, aren’t these two virtually the same? Yes they are! Let’s fit the model above into a connection structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Movie&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;releasedYear&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;coverUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MovieEdge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Movie&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# "node" is a generalized name for an item in a collection&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# The cursor for this result item fits naturally here&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;relevanceFactor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# More metadata only relevant to this result fits here too&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="c"&gt;# All the meta data we'll need to continue paginating&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PageInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;hasNextPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;endCursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;hasPreviousPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;startCursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="c"&gt;# The root type for the pagination. Again, generalized/standardized name&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MovieConnection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;pageInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PageInfo&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MovieEdge&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;searchMovies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MovieConnection&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So, instead of using our own naming schemes, we can easily fit our pagination into the connection based model. But what’s the benefit of doing that? Maybe you disagree with the naming, think it’s too complicated, or you’re at the stage where simple pagination’s the only thing that’s needed for the foreseeable future. Why care?&lt;/p&gt;

&lt;h2&gt;
  
  
  Templating removes decisions so you can focus on other stuff that sparks joy(tm)
&lt;/h2&gt;

&lt;p&gt;It turns our we can take our schema above and template-ize it, so any time we want to paginate a list of &lt;code&gt;Grungle&lt;/code&gt;, we can just fill in the holes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;nounWeWantToPaginate&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="n"&gt;noun&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;noun&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;Edge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;noun&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# "node" is a generalized name for an item in a collection - it's our noun!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# The cursor for this result item fits naturally here&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bits&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pagination&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;our&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;noun&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c"&gt;# All the meta data we'll need to continue paginating&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c"&gt;# This stays the same!&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PageInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;hasNextPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;endCursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;hasPreviousPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;startCursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="c"&gt;# The root type for the pagination. Again, generalized/standardized name&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;noun&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;Connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;pageInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PageInfo&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;[$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;noun&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="n"&gt;Edge&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;${&lt;/span&gt;&lt;span class="n"&gt;noun&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;s(&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;first:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="err"&gt;last:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="err"&gt;after:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="err"&gt;before:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;):&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;noun&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;Connection&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Having a template like this makes it much easier to just drop in pagination for a list of our &lt;code&gt;${noun}&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Standardization == tooling can make your life much easier
&lt;/h2&gt;

&lt;p&gt;More importantly though, conventions what we’ve just built up make it easy for tooling to simplify our lives. Here are a few benefits that connection based pagination bring, and what tooling can do for you:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Future proofed pagination&lt;/strong&gt;&lt;br&gt;
Because the structure provided for connection based pagination give you a logical place to put the things you might eventually need when paginating (like cursors, metadata about additional results and metadata about this specific result item in this specific search), you’re actually future proofing your API when implementing connection based pagination. Even if you don’t need any of the more advanced features we've talked about initially, adding them when you do will be easy since the structure is already there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generalized tooling&lt;/strong&gt;&lt;br&gt;
It’s easy to write generalized tooling. For example, a function that take any &lt;code&gt;${noun}Connection&lt;/code&gt; and return a list of the nodes in the connection, letting you avoid dealing with the somewhat complex structure of connections manually.&lt;/p&gt;

&lt;p&gt;It’s also easy to build tooling on the backend. The same thing applies there - it’s standardized, so you can build generic tooling for it. For example, the template we saw above can be turned into a single &lt;code&gt;makeNounPaginator(…)&lt;/code&gt; so even making pagination on the &lt;em&gt;backend&lt;/em&gt; is easier!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Allow frameworks to do all the heavy lifting for you&lt;/strong&gt;&lt;br&gt;
But, as frontend developers, perhaps the best part of it all is that if it’s standardized, a framework can build on top of it. Relay is an excellent example of this. Pagination in Relay is incredibly ergonomic and easy when you follow the connection spec. &lt;a href="https://dev.to/zth/pagination-with-minimal-effort-in-relay-gl4"&gt;Here’s an article explaining pagination in Relay and what make it great&lt;/a&gt; that we really encourage you to read.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;We hope you’ve gotten a feel for what connection based pagination is and why it makes sense by reading this article. Please feel free to drop us a line in the comments below if you have any questions or comments.&lt;/p&gt;

&lt;p&gt;Also, as mentioned above, you should really continue by reading our article on &lt;a href="https://dev.to/zth/pagination-with-minimal-effort-in-relay-gl4"&gt;pagination in Relay&lt;/a&gt;. Relay leverages what we've talked about here to create a superb developer experience for doing pagination, and is a great example of exactly the type of benefits we mean a standardized structure like connection based pagination enables.&lt;/p&gt;

&lt;p&gt;If you're a member on Egghead and want to see this article in an 11-minute video form, check out Nik Graf's excellent &lt;a href="https://egghead.io/lessons/graphql-paginate-entries-using-the-connection-specification"&gt;Paginate Entries using the Connection Specification&lt;/a&gt; lesson!&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>relay</category>
    </item>
    <item>
      <title>Relay: the GraphQL client that wants to do the dirty work for you</title>
      <dc:creator>Gabriel Nordeborn</dc:creator>
      <pubDate>Thu, 16 Apr 2020 20:44:10 +0000</pubDate>
      <link>https://forem.com/zth/relay-the-graphql-client-that-wants-to-do-the-dirty-work-for-you-55kd</link>
      <guid>https://forem.com/zth/relay-the-graphql-client-that-wants-to-do-the-dirty-work-for-you-55kd</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This series of articles is written by &lt;a href="https://github.com/zth" rel="noopener noreferrer"&gt;Gabriel Nordeborn&lt;/a&gt; and &lt;a href="https://github.com/sgrove" rel="noopener noreferrer"&gt;Sean Grove&lt;/a&gt;. Gabriel is a frontend developer and partner at the Swedish IT consultancy &lt;a href="https://arizon.se" rel="noopener noreferrer"&gt;Arizon&lt;/a&gt; and has been using Relay for a long time. Sean is a co-founder of &lt;a href="https://www.onegraph.com" rel="noopener noreferrer"&gt;OneGraph.com&lt;/a&gt;, unifying 3rd-party APIs with GraphQL.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a series of articles that will dive juuuuust deep enough into Relay to answer - &lt;em&gt;definitively&lt;/em&gt; - one question:&lt;/p&gt;

&lt;p&gt;Why in the world would I care about Relay, Facebook’s JavaScript client framework for building applications using GraphQL?&lt;/p&gt;

&lt;p&gt;It’s a good question, no doubt. In order to answer it, we’ll take you through parts of building a simple page rendering a blog. When building the page, we’ll see two main themes emerge:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Relay is, in fact, an utter workhorse that &lt;em&gt;wants&lt;/em&gt; to do the dirty work for you.&lt;/li&gt;
&lt;li&gt;If you follow the conventions Relay lays out, Relay will give you back a fantastic developer experience for building client side applications using GraphQL.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We’ll also show you that Relay applications are scalable, performant, modular, and resilient to change &lt;em&gt;by default,&lt;/em&gt; and apps built with it are future proofed for the new features in development for React right now.&lt;/p&gt;

&lt;p&gt;Relay comes with a (relatively minor) set of costs, which we’ll examine honestly and up-front, so the tradeoffs are well understood.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting the stage
&lt;/h2&gt;

&lt;p&gt;This article is intended to showcase the ideas and philosophy of &lt;em&gt;Relay&lt;/em&gt;. While we occasionally contrast how Relay does things against other GraphQL frameworks, this article is not primarily intended as a comparison of Relay and other frameworks. We want to talk about and dive deep into &lt;em&gt;Relay&lt;/em&gt; all by itself, explain its philosophy and the concepts involved in building applications with it. &lt;/p&gt;

&lt;p&gt;This also means that the code samples in this article (there are a few!) are only here to illustrate how Relay works, meaning they can be a bit shallow and simplified at times.&lt;/p&gt;

&lt;p&gt;We’ll also focus exclusively on the new &lt;a href="https://relay.dev/docs/en/experimental/step-by-step" rel="noopener noreferrer"&gt;hooks-based APIs for Relay&lt;/a&gt;, which come fully-ready for React’s Suspense and Concurrent Mode. While the new APIs are still marked as experimental, Facebook is rebuilding facebook.com using Relay and said APIs exclusively for the data layer.&lt;/p&gt;

&lt;p&gt;Also, before we start - this article will assume basic familiarity with GraphQL and building client side JavaScript applications. &lt;a href="https://graphql.org/learn/" rel="noopener noreferrer"&gt;Here’s an excellent introduction to GraphQL&lt;/a&gt; if you feel you’re not quite up to speed. Code samples will be in TypeScript, so a basic understanding of that will help too.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Finally&lt;/em&gt;, this article is pretty long. See this as a reference article you can come back to over time.&lt;/p&gt;

&lt;p&gt;With all the disclaimers out of the way, let’s get going!&lt;/p&gt;

&lt;h1&gt;
  
  
  Quick overview of Relay
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Relay is made up of a compiler that optimizes your GraphQL code, and a library you use with React.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before we dive into the deep end of the pool, let’s start with a quick overview of Relay. Relay can be divided into two parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;em&gt;compiler&lt;/em&gt;: responsible for all sorts of optimizations, type generation, and enabling the great developer experience. You keep it running in the background as you develop.&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;library&lt;/em&gt;: the core of Relay, and bindings to use Relay with React.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At this point, all you need to know about the compiler is that it’s a separate process you start that watches and compiles all of your GraphQL operations. You'll hear more about it soon though.&lt;/p&gt;

&lt;p&gt;In addition to this, for Relay to work optimally, it wants your schema to follow three conventions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All &lt;code&gt;id&lt;/code&gt; fields on types should be &lt;em&gt;globally unique&lt;/em&gt; (i.e. no two objects - even two different &lt;em&gt;kinds&lt;/em&gt; of objects - may share the same &lt;code&gt;id&lt;/code&gt; value)&lt;em&gt;.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Node&lt;/code&gt; interface, meaning: objects in the graph should be fetchable via their &lt;code&gt;id&lt;/code&gt; field using a top level &lt;code&gt;node&lt;/code&gt; field. Read more about globally unique id’s and the &lt;code&gt;Node&lt;/code&gt; interface (and why it’s nice!) &lt;a href="https://dev.to/zth/the-magic-of-the-node-interface-4le1"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Pagination should follow the connection based pagination standard. Read more about what connection based pagination is and why it is a good idea &lt;a href="https://dev.to/zth/connection-based-pagination-in-graphql-2588"&gt;in this article&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We won’t dive into the conventions any deeper at this point, but you’re encouraged to check out the articles linked above if you’re interested.&lt;/p&gt;

&lt;h1&gt;
  
  
  At the heart of Relay: the fragment
&lt;/h1&gt;

&lt;p&gt;Let’s first talk about a concept that's at the core of how Relay integrates with GraphQL: Fragments. It’s one of the main keys to Relay (and GraphQL!)'s powers, after all.&lt;/p&gt;

&lt;p&gt;Simply put, fragments in GraphQL are a way to group together common selections on a specific GraphQL type. Here’s an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fragment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Avatar_user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;avatarUrl&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;For the curious: Naming the fragment &lt;code&gt;Avatar_user&lt;/code&gt; is a convention that Relay enforces. Relay wants all fragment names to be globally unique, and to follow the structure of &lt;code&gt;&amp;lt;moduleName&amp;gt;_&amp;lt;propertyName&amp;gt;&lt;/code&gt;. You can read more about naming conventions for fragments &lt;a href="https://relay.dev/docs/en/experimental/a-guided-tour-of-relay#fragments" rel="noopener noreferrer"&gt;here&lt;/a&gt;, and we'll talk about &lt;em&gt;why&lt;/em&gt; this is useful soon.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This defines a fragment called &lt;code&gt;Avatar_user&lt;/code&gt; that can be used with the GraphQL type &lt;code&gt;User&lt;/code&gt;. The fragment selects what’s typically needed to render an avatar. You can then re-use that fragment throughout your queries instead of explicitly selecting all fields needed for rendering the avatar at each place where you need them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c"&gt;# Instead of doing this when you want to render the avatar for the author &lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c"&gt;# and the first two who liked the blog post...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BlogPostQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$blogPostId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;blogPostById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$blogPostId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;avatarUrl&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;likedBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;avatarUrl&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="c"&gt;# ...you can do this&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BlogPostQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$blogPostId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;blogPostById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$blogPostId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="n"&gt;Avatar_user&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;likedBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="n"&gt;Avatar_user&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is convenient because it allows reusing the definition, but more importantly it lets you add and remove fields that are needed to render your avatar as your application evolves &lt;em&gt;in a single place&lt;/em&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fragments allow you to define reusable selections of fields on GraphQL types.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Relay doubles down on fragments
&lt;/h2&gt;

&lt;p&gt;To scale a GraphQL client application over time, it’s a good practice to try and co-locate your data requirements with the components that render said data. This will make maintenance and extending your components much easier, as reasoning about your component and what data it uses is done in a single place. &lt;/p&gt;

&lt;p&gt;Since GraphQL fragments allow you to define sub-selections of fields on specific GraphQL types (as outlined above), they fit the co-location idea perfectly. &lt;/p&gt;

&lt;p&gt;So, a great practice is to define one or more fragments describing the data your component needs to render. This means that a component can say, “I depend on these 3 field from the &lt;code&gt;User&lt;/code&gt; type, regardless of who my parent component is.” In the example above, there would be a component called &lt;code&gt;&amp;lt;Avatar /&amp;gt;&lt;/code&gt; that would show an avatar using the fields defined in the &lt;code&gt;Avatar_user&lt;/code&gt; fragment.&lt;/p&gt;

&lt;p&gt;Now, most frameworks let you use GraphQL fragments one way or another. But Relay takes this further. In Relay, almost &lt;em&gt;everything revolves around fragments&lt;/em&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  How Relay supercharges the GraphQL fragment
&lt;/h1&gt;

&lt;p&gt;At its core, Relay wants every component to have a complete, explicit list of all of its data requirements listed alongside the component itself. This allows Relay to integrate deeply with fragments. Let’s break down what this means, and what it enables.&lt;/p&gt;

&lt;h2&gt;
  
  
  Co-located data requirements and modularity
&lt;/h2&gt;

&lt;p&gt;With Relay, you use fragments to put the component’s data requirements right next to the code that’s actually using it. Following Relay's conventions guarantees that every component explicitly lists every field it needs access to. This means that no component will depend on data it doesn't explicitly ask for, making components modular, self-contained and resilient in the face of reuse and refactoring.&lt;/p&gt;

&lt;p&gt;Relay does a bunch of additional things to enable modularity through using fragments too, which we'll visit a bit later in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;In Relay, components will only re-render when the &lt;em&gt;exact fields&lt;/em&gt; they're using change - with no work on your part! This is because each &lt;em&gt;fragment&lt;/em&gt; will subscribe to updates only for the data it selects. &lt;/p&gt;

&lt;p&gt;That lets Relay optimize how your view is updated by default, ensuring that performance isn’t unnecessary degraded as your app grows. This is quite different to how other GraphQL clients operate. Don’t worry if that didn’t make much sense yet, we’ll show off some great examples of this below and how important it is for scalability.&lt;/p&gt;

&lt;p&gt;With all that in mind, let’s start building our page!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Relay doubles down on the concept of fragments, and uses them to enable co-location of data requirements, modularity and great performance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Building the page to render the blog post
&lt;/h1&gt;

&lt;p&gt;Here’s a wireframe of what our page showing a single blog post will look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropbox.com%2Fs_AECAC5D1357DAAD0F680E7CAD047ACE357666A78B0A066ED11712B9AC877E33E_1583924916777_image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropbox.com%2Fs_AECAC5D1357DAAD0F680E7CAD047ACE357666A78B0A066ED11712B9AC877E33E_1583924916777_image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, let’s think of how we’d approach this with getting all the data for this view through a single top-level query. A very reasonable query to fulfill the wireframe’s need might look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BlogPostQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$blogPostId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;blogPostById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$blogPostId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;avatarUrl&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;shortBio&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;coverImgUrl&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;createdAt&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;slug&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;shortName&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;likedByMe&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;likedBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;totalCount&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;avatarUrl&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One query to fetch all the data we need! Nice!&lt;/p&gt;

&lt;p&gt;And, in turn, the structure of UI components might look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BlogPost&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BlogPostHeader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BlogPostAuthor&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Avatar&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;BlogPostAuthor&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;BlogPostHeader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BlogPostBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BlogPostTitle&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BlogPostMeta&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CreatedAtDisplayer&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TagsDisplayer&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;BlogPostMeta&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BlogPostContent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LikeButton&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LikedByDisplayer&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;LikeButton&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;BlogPostBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;BlogPost&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s have a look at how we’d build this in Relay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Querying for data in Relay
&lt;/h2&gt;

&lt;p&gt;In Relay, the root component rendering the blog post would typically look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// BlogPost.ts&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useLazyLoadQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-relay/hooks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;graphql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-relay&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BlogPostQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./__generated__/BlogPostQuery.graphql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BlogPostHeader&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./BlogPostHeader&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BlogPostBody&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./BlogPostBody&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;blogPostId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BlogPost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;blogPostId&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;blogPostById&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useLazyLoadQuery&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BlogPostQuery&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="s2"&gt;`
          query BlogPostQuery($blogPostId: ID!) {
            blogPostById(id: $blogPostId) {
              ...BlogPostHeader_blogPost
              ...BlogPostBody_blogPost
            }
          }
        `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;blogPostId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;blogPostById&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BlogPostHeader&lt;/span&gt; &lt;span class="nx"&gt;blogPost&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blogPostById&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BlogPostBody&lt;/span&gt; &lt;span class="nx"&gt;blogPost&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blogPostById&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s break down what’s going on here, step by step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;blogPostById&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useLazyLoadQuery&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BlogPostQuery&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="s2"&gt;`
          query BlogPostQuery($blogPostId: ID!) {
            blogPostById(id: $blogPostId) {
              ...BlogPostHeader_blogPost
              ...BlogPostBody_blogPost
            }
          }
        `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;blogPostId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first thing to note is the React hook &lt;code&gt;useLazyLoadQuery&lt;/code&gt; from Relay:&lt;br&gt;
&lt;code&gt;const { blogPostById } = useLazyLoadQuery&amp;lt;BlogPostQuery&amp;gt;&lt;/code&gt;. &lt;code&gt;useLazyLoadQuery&lt;/code&gt; will start fetching &lt;code&gt;BlogPostQuery&lt;/code&gt; as soon as the component renders.&lt;/p&gt;

&lt;p&gt;For type safety, we’re annotating &lt;code&gt;useLazyLoadQuery&lt;/code&gt; to explicitly state the type, &lt;code&gt;BlogPostQuery&lt;/code&gt;, which we import from &lt;code&gt;./__generated__/BlogPostQuery.graphql&lt;/code&gt;. That file is &lt;em&gt;automatically&lt;/em&gt; generated (and kept in sync with changes to the query definition) by the Relay compiler, and has all the type information needed for the query - how the data coming back looks, and what variables the query wants.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer time&lt;/strong&gt;!: As mentioned, &lt;code&gt;useLazyLoadQuery&lt;/code&gt; will start fetching the query as soon as it renders. &lt;strong&gt;However, note that&lt;/strong&gt; Relay actually doesn’t want you to lazily fetch data on render like this. Rather, Relay wants you to start loading your queries as soon as you can, like right when the user is clicking the link to a new page, instead of as the page renders. Why this is so important is talked about at length in this &lt;a href="https://reactjs.org/docs/concurrent-mode-suspense.html#approach-3-render-as-you-fetch-using-suspense" rel="noopener noreferrer"&gt;blog post&lt;/a&gt;, and in &lt;a href="https://www.youtube.com/watch?v=Tl0S7QkxFE4" rel="noopener noreferrer"&gt;this talk&lt;/a&gt;, which we warmly recommend you to read and watch.&lt;br&gt;
We’re still using the lazy load variant in this article though because it's a more familiar mental model for most people, and to keep things as simple and easy to follow as possible. But, please do note that as mentioned above this isn't how you should fetch your query data when building for real with Relay.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next, we have our actual query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="s2"&gt;`
      query BlogPostQuery($blogPostId: ID!) {
        blogPostById(id: $blogPostId) {
          ...BlogPostHeader_blogPost
          ...BlogPostBody_blogPost
      }
    }`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Defining our query, there’s really not a whole lot left of the example query we demonstrated above. Other than selecting a blog post by its id, there’s only two more selections - the fragments for &lt;code&gt;&amp;lt;BlogPostHeader /&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;BlogPostBody /&amp;gt;&lt;/code&gt; on &lt;code&gt;BlogPost&lt;/code&gt;.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Notice that we don’t have to import the fragments we’re using. These are included automatically by the Relay compiler. More about that in a second.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Building your query by composing fragments together like this is very important. Another approach would be to let components define their own &lt;em&gt;queries&lt;/em&gt; and be fully responsible for fetching their own data. While there are a few valid use cases for this, this comes with two major problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A ton of queries are sent to your server instead of just one.&lt;/li&gt;
&lt;li&gt;Each component making their own query would need to wait until they’re actually rendered to start fetching their data. This means your view will likely load quite a lot slower than needed, as requests would probably be made in a waterfall.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;In Relay, we build UIs by composing components together. These components define what data they need themselves in an opaque way.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How Relay enforces modularity
&lt;/h2&gt;

&lt;p&gt;Here’s the mental model to keep in mind with the code above:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As the &lt;code&gt;BlogPost&lt;/code&gt; component, I only know I want to render two children components, &lt;code&gt;BlogPostHeader&lt;/code&gt; and &lt;code&gt;BlogPostBody&lt;/code&gt;. I don’t know what data they need (why would I? That’s their responsibility to know!).&lt;br&gt;
Instead, they’ve told me all the data they need is in a fragment called &lt;code&gt;BlogPostHeader_blogPost&lt;/code&gt; and &lt;code&gt;BlogPostBody_blogPost&lt;/code&gt; on the &lt;code&gt;BlogPost&lt;/code&gt; GraphQL type. As long as I include their fragments in my query, I know I’m guaranteed to get the data they need, even though I don’t know any of the specifics. And when I have the data they need, I'm allowed to render them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We build our UI by composing components that define their own data requirements &lt;em&gt;in isolation&lt;/em&gt;. These components can then be composed together with other components with their own data requirements. However, no component really knows anything about what data other components need, other than from &lt;em&gt;what GraphQL source (type)&lt;/em&gt; the component needs data. Relay takes care of the dirty work, making sure the right component gets the right data, and that all data needed is selected in the query that gets sent to the server. &lt;/p&gt;

&lt;p&gt;This allows you, the developer, to think in terms of &lt;em&gt;components&lt;/em&gt; and &lt;em&gt;fragments&lt;/em&gt; in isolation, while Relay handles all the plumbing for you.&lt;/p&gt;

&lt;p&gt;Moving on!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Relay compiler knows all GraphQL code you’ve defined in your project
&lt;/h2&gt;

&lt;p&gt;Notice that while the query is referencing two fragments, there’s no need to tell it &lt;em&gt;where&lt;/em&gt; or in what file those fragments are defined, or to import them manually to the query. This is because Relay enforces &lt;em&gt;globally unique&lt;/em&gt; names for every fragment, so that the Relay compiler can &lt;em&gt;automatically&lt;/em&gt; include the fragment definitions in any query that's being sent to the server.&lt;/p&gt;

&lt;p&gt;Referencing fragment definitions by hand, another inconvenient, manual, potentially error-prone step, is no longer the developer’s responsibility with Relay.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Using fragments tightly coupled to components allows Relay to hide the data requirements of a component from the outside world, which leads to great modularity and safe refactoring.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally, we get to rendering our results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;      &lt;span class="c1"&gt;// Because we spread both fragments on this object&lt;/span&gt;
      &lt;span class="c1"&gt;// it's guaranteed to satisfy both `BlogPostHeader`&lt;/span&gt;
      &lt;span class="c1"&gt;// and `BlogPostBody` components.&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;blogPostById&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BlogPostHeader&lt;/span&gt; &lt;span class="nx"&gt;blogPost&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blogPostById&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BlogPostBody&lt;/span&gt; &lt;span class="nx"&gt;blogPost&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blogPostById&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we render &lt;code&gt;&amp;lt;BlogPostHeader /&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;BlogPostBody /&amp;gt;&lt;/code&gt;. Looking carefully, you may see that we render both by passing them the &lt;code&gt;blogPostById&lt;/code&gt; object. This is the object in the query where &lt;em&gt;we spread their fragments&lt;/em&gt;. This is the way fragment data is transferred with Relay - passing the object where the fragment has been spread to the component using the fragment, which the component then uses to get the actual fragment data. Don't worry, Relay doesn't leave you hanging. Through the type system Relay will ensure that you're passing the &lt;em&gt;right&lt;/em&gt; object with the &lt;em&gt;right&lt;/em&gt; fragment spread on it. More on this in a bit.&lt;/p&gt;

&lt;p&gt;Whew, that’s a few new things right there! But we’ve already seen and expanded on a number of things Relay does to help us - things that we would normally have to do manually for no additional gain.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Following Relay’s conventions ensures that a component &lt;strong&gt;cannot&lt;/strong&gt; be renderer without it having the data it asks for. This means you’ll have a hard time shipping broken code to production.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s continue moving down the tree of components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a component using fragments
&lt;/h2&gt;

&lt;p&gt;Here's the code for &lt;code&gt;&amp;lt;BlogPostHeader /&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// BlogPostHeader.ts&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useFragment&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-relay/hooks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;graphql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-relay&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;BlogPostHeader_blogPost$key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;BlogPostHeader_blogPost&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./__generated__/BlogPostHeader_blogPost.graphql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BlogPostAuthor&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./BlogPostAuthor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BlogPostLikeControls&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./BlogPostLikeControls&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;blogPost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BlogPostHeader_blogPost$key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BlogPostHeader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;blogPost&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blogPostData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useFragment&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BlogPostHeader_blogPost&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="s2"&gt;`
          fragment BlogPostHeader_blogPost on BlogPost {
            title
            coverImgUrl
            ...BlogPostAuthor_blogPost
            ...BlogPostLikeControls_blogPost
          }
        `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;blogPost&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blogPostData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coverImgUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blogPostData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BlogPostAuthor&lt;/span&gt; &lt;span class="nx"&gt;blogPost&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blogPostData&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BlogPostLikeControls&lt;/span&gt; &lt;span class="nx"&gt;blogPost&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blogPostData&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Our examples here only define one fragment per component, but a component could define &lt;em&gt;any number&lt;/em&gt; of fragments, on &lt;em&gt;any number&lt;/em&gt; of GraphQL types, including multiple fragments on the same type. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s break it down.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;BlogPostHeader_blogPost$key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;BlogPostHeader_blogPost&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./__generated__/BlogPostHeader_blogPost.graphql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We import two type definitions from the file &lt;code&gt;BlogPostHeader_blogPost.graphql&lt;/code&gt;, autogenerated by the Relay compiler for us. &lt;/p&gt;

&lt;p&gt;The Relay compiler will extract the GraphQL fragment code from this file and generate type definitions from it. In fact, it will do that for &lt;em&gt;all&lt;/em&gt; the GraphQL code you write in your project and use with Relay - queries, mutations, subscriptions and fragments. This also means that the types will be kept in sync with any change to the fragment definition automatically by the compiler.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BlogPostHeader_blogPost&lt;/code&gt; contains the type definitions for the fragment, and we pass that to &lt;code&gt;useFragment&lt;/code&gt; (&lt;code&gt;useFragment&lt;/code&gt; which we'll talk more about soon) ensuring that interaction with the data from the fragment is type safe. &lt;/p&gt;

&lt;p&gt;But what on earth is &lt;code&gt;BlogPostHeader_blogPost$key&lt;/code&gt; on line 12 in &lt;code&gt;interface Props { … }&lt;/code&gt;?! Well, it has to do with the type safety. You really &lt;em&gt;really&lt;/em&gt; don’t have to worry about this right now, but for the curious we’ll break it down anyway (the rest of you can just skip to the next heading):&lt;/p&gt;

&lt;p&gt;That type definition ensures, via some dark type magic, that you can only pass the right object (where the &lt;code&gt;BlogPostHeader_blogPost&lt;/code&gt; fragment has been spread) to &lt;code&gt;useFragment&lt;/code&gt;, or you’ll have a type error at build time (in your editor!). As you can see, we take &lt;code&gt;blogPost&lt;/code&gt; from props and pass it to &lt;code&gt;useFragment&lt;/code&gt; as the second parameter. And if &lt;code&gt;blogPost&lt;/code&gt; does not have the right fragment (&lt;code&gt;BlogPostHeader_blogPost&lt;/code&gt;) spread on it, we’ll get a type error. &lt;/p&gt;

&lt;p&gt;It doesn't matter if another fragment with the &lt;em&gt;exact same&lt;/em&gt; data selections has been spread on that object, Relay will make sure it's the &lt;em&gt;exactly right&lt;/em&gt; fragment you want to use with &lt;code&gt;useFragment&lt;/code&gt;. This is important, because it's another way Relay guarantees you can change your fragment definitions without any other component being affected implicitly.&lt;/p&gt;

&lt;p&gt;Relay eliminates another source of potential errors: passing the &lt;em&gt;exact&lt;/em&gt; right object containing the &lt;em&gt;right&lt;/em&gt; fragment.&lt;/p&gt;

&lt;h2&gt;
  
  
  You can only use data you’ve explicitly asked for
&lt;/h2&gt;

&lt;p&gt;We define our fragment &lt;code&gt;BlogPostHeader_blogPost&lt;/code&gt; on &lt;code&gt;BlogPost&lt;/code&gt;. Notice that we explicitly select two fields for this component:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- `title`
- `coverImgUrl`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That’s because &lt;em&gt;we’re using these fields in this specific component&lt;/em&gt;. This highlights another important feature of Relay - data masking. Even if &lt;code&gt;BlogPostAuthor_blogPost&lt;/code&gt;, the next fragment we’re spreading, also selects &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;coverImgUrl&lt;/code&gt; (meaning they &lt;em&gt;must&lt;/em&gt; be available in the query on that exact place where we'll get them from), we won’t get access to them unless we &lt;em&gt;explicitly ask for them&lt;/em&gt; via our own fragment. &lt;/p&gt;

&lt;p&gt;This is enforced both at the type level (the generated types won’t contain them) &lt;em&gt;and&lt;/em&gt; at runtime - the values simply won’t be there even if you bypass your type system.&lt;/p&gt;

&lt;p&gt;This can feel slightly weird at first, but it’s in fact another one of Relay’s safety mechanisms. If you know it’s impossible for other components to implicitly depend on the data you select, you can refactor your components without risking breaking other components in weird, unexpected ways. This is &lt;em&gt;great&lt;/em&gt; as your app grows - again, every component and its data requirements become entirely self-contained.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Enforcing that all data a component requires is explicitly defined means you can’t accidentally break your UI by removing a field selection from a query or fragment that some other component was depending on.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blogPostData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useFragment&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BlogPostHeader_blogPost&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="s2"&gt;`
          fragment BlogPostHeader_blogPost on BlogPost {
            title
            coverImgUrl
            ...BlogPostAuthor_blogPost
            ...BlogPostLikeControls_blogPost
          }
        `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;blogPost&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we're using the React hook &lt;code&gt;useFragment&lt;/code&gt; to get the data for our fragment. &lt;code&gt;useFragment&lt;/code&gt; knows how to take a &lt;em&gt;fragment definition&lt;/em&gt; (the one defined inside the &lt;code&gt;graphql&lt;/code&gt; tag) and an object &lt;em&gt;where that fragment has been spread&lt;/em&gt; (&lt;code&gt;blogPost&lt;/code&gt; here, which comes from &lt;code&gt;props&lt;/code&gt;), and use that to get the data for this particular fragment.&lt;/p&gt;

&lt;p&gt;Just to reiterate that point - no data for this fragment (&lt;code&gt;title&lt;/code&gt;/&lt;code&gt;coverImgUrl&lt;/code&gt;) will be available on &lt;code&gt;blogPost&lt;/code&gt; coming from props - that data will only be available as we call &lt;code&gt;useFragment&lt;/code&gt; with the fragment definition and &lt;code&gt;blogPost&lt;/code&gt;, the object where the fragment has been spread.&lt;/p&gt;

&lt;p&gt;And, just like before, we spread the fragments for the components we want to render - in this case, &lt;code&gt;BlogPostAuthor_blogPost&lt;/code&gt; and &lt;code&gt;BlogPostLikeControls_blogPost&lt;/code&gt; since we're renderering &lt;code&gt;&amp;lt;BlogPostAuthor /&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;BlogPostLikeControls /&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For the curious: since fragments only describes what fields to select, &lt;code&gt;useFragment&lt;/code&gt; won’t make an actual request for data to your GraphQL API. Rather, a fragment &lt;em&gt;must&lt;/em&gt; end up in a query (or other GraphQL operation) at some point in order for its data to be fetched. With that said, Relay has some really cool features which will let you refetch a fragment all by itself. This is possible because Relay can &lt;em&gt;generate queries automatically&lt;/em&gt; for you to refetch specific GraphQL objects by their &lt;code&gt;id&lt;/code&gt;. Anyway, we digress...&lt;/p&gt;

&lt;p&gt;Also, if you know Redux, you can liken &lt;code&gt;useFragment&lt;/code&gt; to a selector that lets you grab only what you need from the state tree.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blogPostData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coverImgUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blogPostData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BlogPostAuthor&lt;/span&gt; &lt;span class="nx"&gt;blogPost&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blogPostData&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BlogPostLikeControls&lt;/span&gt; &lt;span class="nx"&gt;blogPost&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blogPostData&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then render the data we explicitly asked for (&lt;code&gt;coverImgUrl&lt;/code&gt; and &lt;code&gt;title&lt;/code&gt;), and pass the data for the two children components along so they can render. Notice again that we pass the object to the components where we spread their fragments, which is at the root of the fragment &lt;code&gt;BlogPostHeader_blogPost&lt;/code&gt; this component defines and uses.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Relay ensures you stay performant
&lt;/h2&gt;

&lt;p&gt;When you use fragments, each fragment will subscribe to updates only for the data it’s actually using. This means that our &lt;code&gt;&amp;lt;BlogPostHeader /&amp;gt;&lt;/code&gt; component above will only re-render by itself if &lt;code&gt;coverImgUrl&lt;/code&gt; or &lt;code&gt;title&lt;/code&gt; on the specific blog post it’s rendering is updated. If  &lt;code&gt;BlogPostAuthor_blogPost&lt;/code&gt; selects other fields and those update, this component still won’t re-render. Changes to data is subscribed to &lt;em&gt;at the fragment level&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This may sound a bit confusing and perhaps not that useful at first, but it’s incredibly important for performance. Let’s take a deeper look at this by contrasting it to how this type of thing is typically done in when dealing with GraphQL data on the client.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;With Relay, only the components using the data that was updated will re-render when data updates.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Where does the data come from in your view? Contrasting Relay to other frameworks
&lt;/h2&gt;

&lt;p&gt;All data you use in your views must originate from an actual operation that gets data from the server, like a query. You define a query, have your framework fetch it from the server, and then render whatever components you want in your view, passing down the the data they need. The source of the data for most GraphQL frameworks is &lt;em&gt;the query&lt;/em&gt;. Data flows from the query down into components. Here’s an example of how that’s typically done in other GraphQL frameworks (arrows symbolize how data flows):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropbox.com%2Fs_AECAC5D1357DAAD0F680E7CAD047ACE357666A78B0A066ED11712B9AC877E33E_1584360131172_image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropbox.com%2Fs_AECAC5D1357DAAD0F680E7CAD047ACE357666A78B0A066ED11712B9AC877E33E_1584360131172_image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: framework data store is what’s usually referred to as the cache in a lot of frameworks. For this article, assume that &lt;code&gt;"framework data store" === cache&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The flow looks something like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;Profile /&amp;gt;&lt;/code&gt; makes the &lt;code&gt;query ProfileQuery&lt;/code&gt; and a request is issued to the GraphQL API&lt;/li&gt;
&lt;li&gt;The response is stored in some fashion in a framework-specific data store (read: cache)&lt;/li&gt;
&lt;li&gt;The data is delivered to the view for rendering&lt;/li&gt;
&lt;li&gt;The view then continues to pass down pieces of the data to whatever descendant components needs it (&lt;code&gt;Avatar&lt;/code&gt;, &lt;code&gt;Name&lt;/code&gt;, &lt;code&gt;Bio&lt;/code&gt;, etc.). Finally,  your view is rendered&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How Relay does it
&lt;/h2&gt;

&lt;p&gt;Now, Relay does this quite differently. Let’s look at how this illustration looks for Relay:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropbox.com%2Fs_AECAC5D1357DAAD0F680E7CAD047ACE357666A78B0A066ED11712B9AC877E33E_1584360226714_image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropbox.com%2Fs_AECAC5D1357DAAD0F680E7CAD047ACE357666A78B0A066ED11712B9AC877E33E_1584360226714_image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What’s different?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most of the initial flow is the same - the query is issued to the GraphQL API and the data ends up in the framework data store. But then things start to differ. &lt;/li&gt;
&lt;li&gt;Notice that all components which use data get it &lt;em&gt;directly from the&lt;/em&gt; &lt;em&gt;data store (cache)&lt;/em&gt;. This is due to Relay’s deep integration with fragments - in your UI, each fragment gets its own data from the framework data store directly, and &lt;em&gt;does&lt;/em&gt; &lt;em&gt;not&lt;/em&gt; rely on the actual data being passed down to it from the query where its data originated.&lt;/li&gt;
&lt;li&gt;The arrow is gone from the query component down to the other components. We’re still passing some information from the query to the fragment that it uses to look up the data it needs from the data store. But we’re passing no real data to the fragment, all the real data is retrieved by the fragment itself from the data store.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, that’s quite in depth into how Relay and other GraphQL frameworks tend to work. Why should you care about this? Well, this setup enables some pretty neat features.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Other frameworks typically use a query as the source of data, and rely on you passing the data down the tree to other components. Relay flips this around, and lets each component take the data it needs from the data store itself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Performance for free
&lt;/h2&gt;

&lt;p&gt;Think about it: When the query is the source of the data, any update to the data store that affects any data that query has &lt;em&gt;forces a re-render for the component holding the query&lt;/em&gt;, so the updated data can flow down to any component that might use it. This means updates to the data store causes re-renders that must cascade through any number of layers of components that don’t really have anything to do with the update, other than taking data from parent components in order to pass on to children components. &lt;/p&gt;

&lt;p&gt;Relay's approach of each component getting the data it needs from the store directly, and subscribing to updates only for the exact data it uses, ensures that we stay performant even as our app grows in size and complexity.&lt;/p&gt;

&lt;p&gt;This is also important when using subscriptions. Relay makes sure that updated data coming in from the subscription only causes re-renders of the components actually using that updated data.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Using a &lt;code&gt;Query&lt;/code&gt; as the source of data means your entire component tree will be forced to re-render when the GraphQL cache is updated.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Modularity and isolation means you can safely refactor
&lt;/h2&gt;

&lt;p&gt;Removing the responsibility from the developer of routing the data from the query down to whichever component actually &lt;em&gt;needs&lt;/em&gt; said data also removes another chance for developers to mess things up. There’s simply &lt;em&gt;no way&lt;/em&gt; to accidentally (or worse, intentionally) depend on data that should just be passing through down the component tree if you can't access it. Relay again makes sure it does the heavy work for you when it can.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Using Relay and its fragment-first approach means it's really hard to mess up the data flow in a component tree.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It should of course be noted though that most of the cons of the “query as the source of data” approach can be somewhat mitigated by old fashioned manual optimization - &lt;code&gt;React.memo&lt;/code&gt;, &lt;code&gt;shouldComponentUpdate&lt;/code&gt; and so on. But that’s both potentially a performance problem in itself, and also prone to mistakes (the more fiddly a task, the more likely humans are to eventually mess it up). Relay on the other hand will make sure you stay performant without needing to think about it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Each component receiving its own data from the cache also enables some really cool advanced features of Relay, like partially rendering views with the data that’s already available in the store while waiting for the full data for the view to come back. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Summarizing fragments
&lt;/h2&gt;

&lt;p&gt;Let’s stop here for a bit and digest what type of work Relay is doing for us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Through the type system, Relay is making sure this component &lt;em&gt;cannot&lt;/em&gt; be rendered without the &lt;em&gt;exact&lt;/em&gt; right object from GraphQL, containing its data. One less thing we can mess up.&lt;/li&gt;
&lt;li&gt;Since each component using fragments will only update if the exact data it uses updates, updates to the cache is performant by default in Relay.&lt;/li&gt;
&lt;li&gt;Through type generation, Relay is ensuring that any interaction with this fragment's data is type safe. Worth highlighting here is that type generation is a core feature of the Relay compiler.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Relay’s architecture and philosophy takes advantage of how much information is available about your components to the computer, from the data dependencies of components, to the data and its types offered by the server. It uses all this and more to do all sorts of work that normally we - the developers who have &lt;em&gt;plenty&lt;/em&gt; to do already - are required to deal with.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's easy to underestimate how quickly views become complex. Complexity and performance is handled by default through the conventions Relay force you to follow.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This brings some real power to you as a developer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can build composable components that are almost completely isolated.&lt;/li&gt;
&lt;li&gt;Refactoring your components will be fully safe, and Relay will ensure you’re not missing anything or messing this up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The importance of this once you start building a number of reusable components cannot be overstated. It’s &lt;em&gt;crucial&lt;/em&gt; for developer velocity to have refactoring components used in large parts of the code base be safe.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As your app grows, the ease and safety of refactoring becomes crucial to continue moving fast.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Wrapping up our introduction to Relay
&lt;/h1&gt;

&lt;p&gt;We’ve covered a lot of ground in this article. If you take anything with you, let it be that Relay &lt;em&gt;forces&lt;/em&gt; you to build scalable, performant, type safe applications that will be easy and safe to maintain and refactor.&lt;/p&gt;

&lt;p&gt;Relay really does do your dirty work for you, and while a lot of what we’ve shown will be possible to achieve through heroic effort with other frameworks, we hope we’ve shown the powerful benefits that &lt;em&gt;enforcing&lt;/em&gt; these patterns can bring. Their importance cannot be overstated.&lt;/p&gt;

&lt;h2&gt;
  
  
  A remarkable piece of software
&lt;/h2&gt;

&lt;p&gt;Relay is really a remarkable piece of software, built from the blood, sweat, tears, and most importantly - experience and deep insight - of shipping and maintaining products using GraphQL for a long time.&lt;/p&gt;

&lt;p&gt;Even though this article is pretty long and fairly dense, we've barely scratched the surface of what Relay can do. Let's end this article with a list detailing some of what more Relay can do that we haven't covered in this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mutations with optimistic and complex cache updates&lt;/li&gt;
&lt;li&gt;Subscriptions&lt;/li&gt;
&lt;li&gt;Fully integrated with (and heavily leveraging) Suspense and Concurrent Mode - ready for the next generation of React&lt;/li&gt;
&lt;li&gt;Use Relay to manage your local state through Relay, enjoying the general benefits of using Relay also for local state management (like integration with Suspense and Concurrent Mode!)&lt;/li&gt;
&lt;li&gt;Streaming list results via &lt;code&gt;@stream&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Deferring parts of the server response that might take a long time to load via &lt;code&gt;@defer&lt;/code&gt;, so the rest of the UI can render faster&lt;/li&gt;
&lt;li&gt;Automatic generation of queries for refetching fragments and pagination&lt;/li&gt;
&lt;li&gt;Complex cache management; control how large the cache is allowed to get, and if data for your view should be resolved from the cache or the network (or both, or first the cache and then the network)&lt;/li&gt;
&lt;li&gt;A stable, mature and flexible cache that &lt;em&gt;Just Works (tm)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Preload queries for new views as soon as the user indicates navigation is about to happen
_ Partially render views with any data already available in the store, while waiting for the query data to arrive&lt;/li&gt;
&lt;li&gt;Define arguments for fragments (think like props for a component), taking composability of your components to the next level&lt;/li&gt;
&lt;li&gt;Teach Relay more about how the data in your graph is connected than what can be derived from your schema, so it can resolve more data from the cache (think "these top-level fields with these variables resolve the same User")&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article ends here, but we really encourage you to go on and read the article on pagination in Relay. Pagination in Relay bring together the powerful features of Relay in a beautiful way, showcasing just how much automation and what incredible DX is possible when you let a framework do all the heavy lifting. &lt;a href="https://dev.to/zth/pagination-with-minimal-effort-in-relay-gl4"&gt;Read it here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s a few other articles you can continue with too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/zth/the-magic-of-the-node-interface-4le1"&gt;The magic of the &lt;code&gt;Node&lt;/code&gt; interface&lt;/a&gt;. An article about the &lt;code&gt;Node&lt;/code&gt; interface, globally unique IDs and what power those things bring.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/zth/connection-based-pagination-in-graphql-2588"&gt;Connection based pagination&lt;/a&gt;. An introduction to why doing connection based pagination is a good idea.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

&lt;h1&gt;
  
  
  Special thanks
&lt;/h1&gt;

&lt;p&gt;Many thanks to Xavier Cazalot, Arnar Þór Sveinsson, Jaap Frolich, Joe Previte, Stepan Parunashvili, and Ben Sangster for thorough feedback on the drafts of this article!&lt;/p&gt;

</description>
      <category>react</category>
      <category>graphql</category>
      <category>relay</category>
    </item>
  </channel>
</rss>
