Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Efficient Data Fetching with GraphQL and Relay
Search
Dan Schafer
July 22, 2015
Programming
420
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Efficient Data Fetching with GraphQL and Relay
Presented at
http://www.meetup.com/ReactJS-San-Francisco/events/223945265/
Dan Schafer
July 22, 2015
More Decks by Dan Schafer
See All by Dan Schafer
The Prehistory of GraphQL
dschafer
1
430
GraphQL: Client-Driven Development
dschafer
0
360
GraphQL at Facebook
dschafer
0
220
GraphQL: A Horizontal Platform
dschafer
2
270
Other Decks in Programming
See All in Programming
機械に任せるテスト、人が見るテスト ⽣成AIで引き直した、運⽤保守フェーズの線引き
dske104
0
180
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
580
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
710
HTML-in-Canvasで作る未来のWeb UI表現
clockmaker
3
4.4k
Java 27新機能 / Java 27 new features
kishida
2
220
パズルゲームの作り方 / how to make puzzle games
kaityo256
PRO
2
280
phperだってパンチカードでコーディングしたい
o0h
PRO
0
270
Apple Intelligence を用いた個人情報誤送信防止、及びユーザーリクエスト体験の改善について
yukiny
0
330
[2026-09-26]空論ジェネリックプロセス~テスト資産とAIで紡ぐ、再現可能なパフォーマンスチューニングの話~
tosite
0
260
Herb in Rails 8.2: Your ERB views, now HTML-aware @ Rails World 2026, Austin, Texas
marcoroth
0
200
Simple Storage Service(S3) is not simple
iwatsukayura
0
260
設計次第でAIコードの読む量は減らせる / designing-for-code-reading
minodriven
34
16k
Featured
See All Featured
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
450
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.6k
We Have a Design System, Now What?
morganepeng
55
8.4k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.4k
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
540
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3.2k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6.1k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
450
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
1k
Chasing Engaging Ingredients in Design
codingconduct
0
350
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
620
The Language of Interfaces
destraynor
162
27k
Transcript
Efficient Data Fetching with GraphQL and Relay Dan Schafer Facebook
Product Infrastructure @dlschafer
Flux
Flux Dispatcher Action Store View Action
Flux Dispatcher Action Store View Action Server
Flux Dispatcher Action Store View Action Server
None
None
<FriendList>
<FriendList> <FriendListItem>
<FriendList> <FriendListItem> <FriendInfo>
Server <FriendList> <FriendListItem> <FriendInfo>
Server <FriendList> <FriendListItem> <FriendInfo>
Server <FriendList> <FriendListItem> <FriendInfo>
Server <FriendList> <FriendListItem> <FriendInfo>
Server <FriendList> <FriendListItem> <FriendInfo>
Server <FriendList> <FriendListItem> <FriendInfo>
Server <FriendList> <FriendListItem> <FriendInfo>
Server <FriendList> <FriendListItem> <FriendInfo>
Server <FriendList> <FriendListItem> <FriendInfo>
Server <FriendList> <FriendListItem> <FriendInfo>
Server <FriendList> <FriendListItem> <FriendInfo>
Server <FriendList> <FriendListItem> <FriendInfo>
Server <FriendList> <FriendListItem> <FriendInfo>
Server <FriendList> <FriendListItem> <FriendInfo>
Server <FriendList> <FriendListItem> <FriendInfo>
Response Shape
Composition
Composition <FriendListItem> <FriendInfo>
Composition <FriendListItem> <FriendInfo>
Composition <FriendListItem> <FriendInfo>
None
None
{ id: 3500401,
{ id: 3500401, name: "Jing Chen",
{ id: 3500401, name: "Jing Chen", isViewerFriend: true,
{ id: 3500401, name: "Jing Chen", isViewerFriend: true, mutualFriends: {
count: 195 },
{ id: 3500401, name: "Jing Chen", isViewerFriend: true, mutualFriends: {
count: 195 }, profilePicture: { uri: "http://…", width: 50, height: 50 } }
{ id: 3500401, name: "Jing Chen", isViewerFriend: true, mutualFriends: {
count: 195 }, profilePicture: { uri: "http://…", width: 50, height: 50 } }
{ id name isViewerFriend mutualFriends { count } profilePicture {
uri width height } }
{ id name isViewerFriend mutualFriends { count } profilePicture {
uri width height } }
GraphQL
GraphQL { { "id": "1572451031", "name": "Daniel Schafer" } }
GraphQL { { "id": "1572451031", "name": "Daniel Schafer" } }
{ id name }
GraphQL { "node": { "id": "1572451031", "name": "Daniel Schafer" }
} { node(id: 1572451031) { id name } }
GraphQL { "node": { "id": "1572451031", "name": "Daniel Schafer" }
} { node(id: 1572451031) { id name birthdate { month day } } }
GraphQL { "node": { "id": "1572451031", "name": "Daniel Schafer", "birthdate":
{ "month": 1, "day": 17, } } } { node(id: 1572451031) { id name birthdate { month day } } }
GraphQL + React
None
None
GraphQL + React
var FriendInfo = React.createClass({ render: function() { return ( <div>
<span>{this.props.user.name}</span> <span>{this.props.user.mutualFriends.count} mutual friends</span> </div> ); } }); GraphQL + React
var FriendInfo = React.createClass({ statics: { queries: { } }
render: function() { return ( <div> <span>{this.props.user.name}</span> <span>{this.props.user.mutualFriends.count} mutual friends</span> </div> ); } }); GraphQL + React
var FriendInfo = React.createClass({ statics: { queries: { user: function()
{ return graphql` User { name mutualFriends { count } } `; } } }, render: function() { return ( <div> <span>{this.props.user.name}</span> <span>{this.props.user.mutualFriends.count} mutual friends</span> </div> ); } }); GraphQL + React
var FriendInfo = React.createClass({ statics: { queries: { user: function()
{ return graphql` User { name mutualFriends { count } } `; } } }, render: function() { return ( <div> <span>{this.props.user.name}</span> <span>{this.props.user.mutualFriends.count} mutual friends</span> </div> ); } }); GraphQL + React
var FriendInfo = React.createClass({ statics: { queries: { user: function()
{ return graphql` User { name mutualFriends { count } } `; } } }, render: function() { return ( <div> <span>{this.props.user.name}</span> <span>{this.props.user.mutualFriends.count} mutual friends</span> </div> ); } }); GraphQL + React
var FriendInfo = React.createClass({ statics: { queries: { user: function()
{ return graphql` User { name mutualFriends { count } } `; } } }, render: function() { return ( <div> <span>{this.props.user.name}</span> <span>{this.props.user.mutualFriends.count} mutual friends</span> </div> ); } }); GraphQL + React
var FriendInfo = React.createClass({ statics: { queries: { user: function()
{ return graphql` User { name mutualFriends { count } } `; } } }, render: function() { return ( <div> <span>{this.props.user.name}</span> <span>{this.props.user.mutualFriends.count} mutual friends</span> </div> ); } }); GraphQL + React
Composition
None
None
Composition
Composition var FriendListItem = React.createClass({ render: function() { return (
<div> <ProfilePic user={this.props.user} /> <FriendInfo user={this.props.user} /> </div> ); } });
Composition var FriendListItem = React.createClass({ statics: { queries: { user:
function() { return graphql` User { ?? ?? } `; } } }, render: function() { return ( <div> <ProfilePic user={this.props.user} /> <FriendInfo user={this.props.user} /> </div> ); } });
Composition var FriendListItem = React.createClass({ statics: { queries: { user:
function() { return graphql` User { ${ProfilePic.getQuery(‘user’)}, ${FriendInfo.getQuery(‘user’)} } `; } } }, render: function() { return ( <div> <ProfilePic user={this.props.user} /> <FriendInfo user={this.props.user} /> </div> ); } });
Lifecycle
Lifecycle var FriendListItem = React.createClass({ statics: { queries: { user:
function() { return graphql` User { ${ProfilePic.getQuery('user')} ${FriendInfo.getQuery('user')} } `; } } } }); Static View
Lifecycle var FriendListItem = React.createClass({ statics: { queries: { user:
function() { return graphql` User { ${ProfilePic.getQuery('user')} ${FriendInfo.getQuery('user')} } `; } } } }); Static View FriendListItem
Lifecycle Query { ')} ')} Static View
Lifecycle Query { ')} ')} Static View ProfilePic FriendInfo FriendListItem
Lifecycle Query Server ew
Lifecycle { node(id: 1572451031) { name mutualFriends { count },
profilePicture { uri width height } } } Query Server ew
Lifecycle y Server Data
Lifecycle { "node": { name: "Daniel Schafer", mutualFriends: { count:
195 }, profilePicture: { uri: "http://...", width: 50, height: 50 } } } y Server Data
Lifecycle Server Data Store
Lifecycle Server Data Store Flux
Lifecycle a Store Views
Lifecycle <div> <ProfilePic user={this.props.user} /> <FriendInfo user={this.props.user} /> </div> a
Store Views
Lifecycle Query Server Data Store Views Static View
var FriendInfo = React.createClass({ statics: { queries: { user: function()
{ return graphql` User { name mutualFriends { count } } `; } } }, render: function() { return ( <div> <span>{this.props.user.name}</span> <span>{this.props.user.mutualFriends.count} mutual friends</span> </div> ); } }); Response Shape
Lifecycle Query Server Data Store Views Static View
Relay
Pagination
Pagination { "1572451031": { "name": "Daniel Schafer" } } {
node(id: 1572451031) { name } }
Pagination { "1572451031": { "name": "Daniel Schafer" } } {
node(id: 1572451031) { name friends { name } } }
Pagination { "1572451031": { "name": "Daniel Schafer", "friends": [ {
"name": "Jing Chen" }, { "name": "Lee Byron" }, { "name": "Nick Schrock" }, { "name": "Joe Savona" } ] } } { node(id: 1572451031) { name friends { name } } }
Pagination { "1572451031": { "name": "Daniel Schafer", "friends": [ {
"name": "Jing Chen" }, { "name": "Lee Byron" }, { "name": "Nick Schrock" }, { "name": "Joe Savona" } ] } } { node(id: 1572451031) { name friends(first: 2) { name } } }
Pagination { "1572451031": { "name": "Daniel Schafer", "friends": [ {
"name": "Jing Chen" }, { "name": "Lee Byron" } ] } } { node(id: 1572451031) { name friends(first: 2) { name } } }
Pagination { "1572451031": { "name": "Daniel Schafer", "friends": [ {
"name": "Jing Chen" }, { "name": "Lee Byron" } ] } } { node(id: 1572451031) { name friends(first: 2 offset: 2) { name } } }
Offsets? Offset 0 Offset 1
Offsets? Offset 0 Offset 1
Offsets? Offset 0 Offset 1
Offsets? Offset 1 Offset 2 Offset 0
Offsets?
None
Cursors
Cursors { "1572451031": { "name": "Daniel Schafer", "friends": [ {
"name": "Jing Chen" }, { "name": "Lee Byron" } ] } } { node(id: 1572451031) { name friends(first: 2) { name } } }
Cursors { "1572451031": { "name": "Daniel Schafer", "friends": [ {
"name": "Jing Chen" }, { "name": "Lee Byron" } ] } } { node(id: 1572451031) { name friends(first: 2) { edges { node { name } cursor } } } }
Cursors { "1572451031": { "name": "Daniel Schafer", "friends": { "edges":
[ { "node": { "name": "Jing Chen" }, "cursor": "3500401" }, { "node": { "name": "Lee Byron" }, "cursor": "4802170" } ] } } } { node(id: 1572451031) { name friends(first: 2) { edges { node { name } cursor } } } }
Cursors { "1572451031": { "name": "Daniel Schafer", "friends": { "edges":
[ { "node": { "name": "Jing Chen" }, "cursor": "3500401" }, { "node": { "name": "Lee Byron" }, "cursor": "4802170" } ] } } } { node(id: 1572451031) { name friends(first: 2 after: 4802170) { edges { node { name } cursor } } } }
Cursors { "1572451031": { "name": "Daniel Schafer", "friends": { "edges":
[ { "node": { "name": "Jing Chen" }, "cursor": "3500401" }, { "node": { "name": "Lee Byron" }, "cursor": "4802170" } ] } } } { node(id: 1572451031) { name friends(first: 2 after: 4802170) { edges { node { name } cursor } } } } { "1572451031": { "name": "Daniel Schafer", "friends": { "edges": [ { "node": { "name": "Nick Schrock" }, "cursor": "37000641" }, { "node": { "name": "Joe Savona" }, "cursor": "842472" } ] } } }
Cursors { "1572451031": { "name": "Daniel Schafer", "friends": { "edges":
[ { "node": { "name": "Jing Chen" }, "cursor": "3500401" }, { "node": { "name": "Lee Byron" }, "cursor": "4802170" } ] } } } { node(id: 1572451031) { name friends(first: 2 after: 842472) { edges { node { name } cursor } } } } { "1572451031": { "name": "Daniel Schafer", "friends": { "edges": [ { "node": { "name": "Nick Schrock" }, "cursor": "37000641" }, { "node": { "name": "Joe Savona" }, "cursor": "842472" } ] } } }
Cursors { "1572451031": { "name": "Daniel Schafer", "friends": { "edges":
[ { "node": { "name": "Jing Chen" }, "cursor": "3500401" }, { "node": { "name": "Lee Byron" }, "cursor": "4802170" } ] } } } { node(id: 1572451031) { name friends(first: 2 after: 842472) { edges { node { name } cursor } } } } { "1572451031": { "name": "Daniel Schafer", "friends": { "edges": [] } } }
Cursors { "1572451031": { "name": "Daniel Schafer", "friends": { "edges":
[ { "node": { "name": "Jing Chen" }, "cursor": "3500401" }, { "node": { "name": "Lee Byron" }, "cursor": "4802170" } ] } } } { node(id: 1572451031) { name friends(first: 2) { edges { node { name } cursor } } } }
Cursors { "1572451031": { "name": "Daniel Schafer", "friends": { "edges":
[ { "node": { "name": "Jing Chen" }, "cursor": "3500401" }, { "node": { "name": "Lee Byron" }, "cursor": "4802170" } ] } } } { node(id: 1572451031) { name friends(first: 2) { edges { node { name } cursor } pageInfo { hasNextPage } } } } { "1572451031": { "name": "Daniel Schafer", "friends": { "edges": [ { "node": { "name": "Jing Chen" }, "cursor": "3500401" }, { "node": { "name": "Lee Byron" }, "cursor": "4802170" } ] } } }
Cursors { "1572451031": { "name": "Daniel Schafer", "friends": { "edges":
[ { "node": { "name": "Jing Chen" }, "cursor": "3500401" }, { "node": { "name": "Lee Byron" }, "cursor": "4802170" } ] } } } { node(id: 1572451031) { name friends(first: 2) { edges { node { name } cursor } pageInfo { hasNextPage } } } } { "1572451031": { "name": "Daniel Schafer", "friends": { "edges": [ { "node": { "name": "Jing Chen" }, "cursor": "3500401" }, { "node": { "name": "Lee Byron" }, "cursor": "4802170" } ], "pageInfo": { "hasNextPage": true }, } }
Cursors { "1572451031": { "name": "Daniel Schafer", "friends": { "edges":
[ { "node": { "name": "Jing Chen" }, "cursor": "3500401" }, { "node": { "name": "Lee Byron" }, "cursor": "4802170" } ] } } } { node(id: 1572451031) { name friends(first: 2 after: 4802170) { edges { node { name } cursor } pageInfo { hasNextPage } } } } { "1572451031": { "name": "Daniel Schafer", "friends": { "edges": [ { "node": { "name": "Jing Chen" }, "cursor": "3500401" }, { "node": { "name": "Lee Byron" }, "cursor": "4802170" } ], "pageInfo": { "hasNextPage": true }, } }
Cursors { "1572451031": { "name": "Daniel Schafer", "friends": { "edges":
[ { "node": { "name": "Jing Chen" }, "cursor": "3500401" }, { "node": { "name": "Lee Byron" }, "cursor": "4802170" } ] } } } { node(id: 1572451031) { name friends(first: 2 after: 4802170) { edges { node { name } cursor } pageInfo { hasNextPage } } } } { "1572451031": { "name": "Daniel Schafer", "friends": { "edges": [ { "node": { "name": "Nick Schrock" }, "cursor": "37000641" }, { "node": { "name": "Joe Savona" }, "cursor": "842472" } ], "pageInfo": { "hasNextPage": false }, } }
Connections in Relay
Connections in Relay var FriendList = React.createClass({ render: function() {
return ( <div> { this.props.viewer.friends.map( function(user) { return <FriendListItem user={user} />; } ) } </div> ); } });
Connections in Relay var FriendList = React.createClass({ statics: { queries:
{ viewer: function() { return graphql` Viewer { friends { ${FriendListItem.getQuery(‘user’)}, } } `; } } }, render: function() { ... } });
Connections in Relay var FriendList = React.createClass({ statics: { queries:
{ viewer: function() { return graphql` Viewer { friends(first: 10) { ${FriendListItem.getQuery(‘user’)}, } } `; } } }, render: function() { ... } });
Cursors
None
Declarative Pagination
Connections in Relay var FriendList = React.createClass({ statics: { queries:
{ viewer: function() { return graphql` Viewer { friends(first: 10) { ${FriendListItem.getQuery(‘user’)}, } } `; } } }, render: function() { ... } });
Connections in Relay var FriendList = React.createClass({ statics: { queryParams:
{count: 10}, queries: { viewer: function(params) { return graphql` Viewer { friends(first: ${params.count}) { ${FriendListItem.getQuery(‘user’)}, } } `; } } }, render: function() { ... } });
Connections in Relay var FriendList = React.createClass({ statics: { queryParams:
{count: 10}, queries: { viewer: function(params) { return graphql` Viewer { friends(first: ${params.count}) { ${FriendListItem.getQuery(‘user’)}, } } `; } } }, onScrollLoad: function() { this.setQueryParams({count: this.queryParams.count + 5}); }, render: function() { ... } });
Mutations
Subscriptions
Relay August 2015
GraphQL https://github.com/facebook/graphql https://github.com/graphql/graphql-‐js
Thanks! Dan Schafer @dlschafer