The first piece of functionality that you’ll implement in the app is loading and displaying a list of
Link elements. You’ll walk up our way in the React component hierarchy and start with the component that’ll render a single link.
This is a simple React component that expects a
link in its
props and renders the link’s
url. Easy as pie! 🍰
Next, you’ll implement the component that renders a list of links.
Here, you’re using mock data for now to make sure the component setup works. You’ll soon replace this with some actual data that’s loaded from the server - patience, young Padawan!
Note: The project that was generated by
create-react-appuses semicolons and double quotes for strings. All the code that you’re going to write in this tutorial will use no semicolons and single quotes.
Run the app by calling
yarn start to check if everything works so far! The app should now display the two links from the
In this section, you’ll learn how you can actually load data from the server instead of rendering the links simply from a local array.
But before you go and make the required changes, a bit of theory!
One of the most powerful concepts of Relay is called colocation. This means that a React component declares its data dependencies right next to (i.e. in the same file) where it’s defined. This happens in the form of GraphQL fragments.
This effectively means that you’ll never write any actual GraphQL queries yourself. This is unlike the approach that’s taken in Apollo, where you’re also able to colocate data dependencies and React components - but are most commonly doing so by writing actual queries instead of fragments.
But if you’re never writing any queries in Relay, how can the GraphQL server respond with sensible data?
That’s the cool part about Relay! Under the hood, it will figure out the most efficient way for your React components to fetch the data that’s required for them to render, based on the data dependencies they declared in their fragments.
You don’t have to worry about fetching the data one bit - all networking and caching logic is abstracted away and you can focus on writing your React components and what data they need! Declarative data fetching ftw 😎
The way to declare the data dependencies alongside your React components is by using the
createFragmentContainer is a higher-order component that takes in two arguments:
Go ahead and write the fragment containers for the two components that you added before.
All that’s done there is importing the required Relay modules that you need to create the fragment container.
Here’s where it gets interesting! Let’s examine this part step-by-step:
You’re using the
createFragmentContainer higher-order component and pass in two arguments - exactly as we said before. The first argument is simply the React component, here that’s the
Link. The second argument are its data requirements in the form of a GraphQL fragment tagged with the
graphql function. The
Link component needs access to the
url of a link item. The
id is required so that Relay can uniquely identify the link items when storing and retrieving them in the cache.
One important note here is that there is a naming convention for the fragments you’re creating! Each fragment should be named according to the file and the prop that will get injected into the component:
In your case, the file is called
Link.js and the prop in the component should be called
link. So you end up with
Link_link for the name of the fragment.
Great work so far! Go and add the the fragment container for
LinkList as well.
Similar to the
Link component, you’re passing the
LinkList component along with its data requirements into
LinkList needs access to a list of links - here you’re simply asking for the last 100 links to display. In the last chapter of this tutorial, you’ll implement a proper pagination approach.
Note: In Relay, lists are represented with the concept of connections. This facilitates the implementation of a cursor-based pagination approach on the client. Relay also requires you to always specify a limit of items that you want to fetch from the server, so you have to pass the
lastargument when fetching items from a connection.
Notice that you’re again following the same naming convention and name the fragment
LinkList.js is the name of the file and
viewer is the prop that you expect in the component.
You’re also reusing the
Link_link fragment that you wrote in
Link.js. That’s because the
LinkList is higher in the React component (and Relay container) tree, so it needs to include all the fragments of its children!
@connection directive is required for updating the cache later on - you need it so you can refer to that particular connection (identified by the key
LinkList_allLinks) in the cache.
Finally, you also need to delete the mock data and use the data that’ll be injected by Relay to render the
Now it starts to get interesting! What happens with these fragments? When are they used and what’s the query Relay actually sends to the server?
QueryRendereris the root of a Relay tree. It takes a query, fetches the data and calls the
rendercallback with the data.
So, here is where it all adds up. React components are wrapped with GraphQL fragments to become Relay containers. When doing so, they retain the same hierarchical structure as the pure React components and form a tree. At the root of that tree there’s the
QueryRenderer, which also is a higher-order component that will take care of composing the actual query.
So, go and add the
QueryRenderer in a new component!
QueryRenderer needs at least three things when being instantiated:
environmentwhich is why you’re importing it here.
querywhich will be the basis for the query that gets sent to the server.
renderfunction that specifies what should be rendered in loading, error and success cases.
You’ll write the root
Notice how you’re now actually reusing the fragment
LinkList_viewer from the
As discussed before, you’re using the
QueryRenderer and provide the three required props. The
render function receives the result that’s returned by the server and passes it down to its children.
Lastly, you need to make sure that the
LinkListPage is rendered on the root of your component hierarchy.
If you’re just running the app now, you’ll be disappointed that it throws some errors:
Failed to compile. ./src/components/LinkListPage.js Module not found: Can't resolve './__generated__/LinkListPageQuery.graphql' in '.../hackernews-react-relay/src/components'
That’s because we’ve skipped the compilation of the GraphQL code that makes for much of Relay’s actual power! You already installed the
relay-compiler, so now you’ll actually use it.
The compiler can be invoked using the
relay-compiler command in the terminal where you have to provide two arguments:
--src: The path to all your files that contain
--schema: The path to your full GraphQL schema that you already downloaded in the previous chapter
Now - when running the
relay-compiler you’ll actually see another error message. That’s disappointing, but don’t worry - it’s not your fault this time. This happens because of a bug in the Relay Compiler that breaks the compilation when there are non-nullable types on the connection types in the schema. You can work around the the issue by manually adjusting it, which is not something you should be doing under normal circumstances but for the purpose of this tutorial it will be fine.
Now you can run the Relay Compiler again!
relay-compiler will now scan all files in
src and look for
Here’s what the terminal output will look like:
$ relay-compiler --src ./src --schema ./schema.graphql HINT: pass --watch to keep watching for changes. Parsed default in 0.06s Writing default Writer time: 0.27s [0.08s compiling, 0.19s generating, 0.00s extra] Created: - Link_link.flow.js - Link_link.graphql.js - LinkList_viewer.flow.js - LinkList_viewer.graphql.js - LinkListPageQuery.graphql.js Unchanged: 0 files Written default in 0.33s
You’ll also notice that the
__generated__ directory was now created and contains all the files that were generated by the compiler:
. └── src └── components └── __generated__ ├── LinkListPageQuery.graphql.js ├── LinkList_viewer.flow.js ├── LinkList_viewer.graphql.js ├── Link_link.flow.js └── Link_link.graphql.js
That’s it, you can now run the app and you’ll see the same links that you initially added with the two mutations in the Playground rendered in the app!
By the way, if you’re curios to see what the actual query looked like that the
QueryRenderer composed for you and that was sent over to the server, you can inspect the Networking-tab of your browser’s dev tools:
Awesome! You can now move on to learn about mutations in Relay.