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
Transcript
122 slides
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
More Decks by Dan Schafer
See All by Dan Schafer
The Prehistory of GraphQL
dschafer
1
430
GraphQL: Client-Driven Development
dschafer
0
370
GraphQL at Facebook
dschafer
0
220
GraphQL: A Horizontal Platform
dschafer
2
270
Other Decks in Programming
See All in Programming
Kawaiicon: Kubernetes, it's no longer cool, but let's secure it anyway!
barnbarn
0
130
Long Living Tokens, Die, Die, Die! (or: The One Ring is Banned in Modern)
sylph01
0
420
Materialが消えた日 〜真っ白なFlutterキャンバスにRenderObjectで絵を描く〜
umigishiaoi
0
160
Modernizing iOS Apps
seyfoyun
0
150
クラウドエージェントは、 何がそんなに便利なのか / what makes cloud agents so useful
rkaga
5
850
Optunaを作ったときにやりたかったこと、その後 (2026/10/16, Optuna Meetup #3)
iwiwi
4
1.5k
クラウドゲーミングのパフォーマンス最適化に挑む / Cloud Gaming Performance Tuning
vivion
0
330
PumaからFalconに移行したRailsアプリケーションでの実践
falcon8823
0
380
作って学ぶSpring BootのAuto Configuration / JJUG Night Seminar 2026-10-19
rshindo
0
230
Lambda durable functionsでHuman in the Loopを楽に…楽に……
har1101
2
300
あなたの await、OS まで届いてる? strace で覗く JavaScript の非同期
hasutosasaki
1
2.3k
エージェントを使い続けるためのメタワーク / Meta-work for keeping using the agent
rkaga
6
2.3k
Featured
See All Featured
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.9k
Fireside Chat
paigeccino
43
4.1k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
330
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
620
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
760
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.7k
Odyssey Design
rkendrick25
PRO
3
940
Thoughts on Productivity
jonyablonski
76
5.5k
Claude Code のすすめ
schroneko
67
230k
Testing 201, or: Great Expectations
jmmastey
46
8.4k
ラッコキーワード サービス紹介資料
rakko
5
5.8M