Successfully reported this slideshow.
Your SlideShare is downloading. ×

Getting Started with Relay Modern

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Upcoming SlideShare
GraphQL And Relay Modern
GraphQL And Relay Modern
Loading in …3
×

Check these out next

1 of 63 Ad

More Related Content

Slideshows for you (18)

Similar to Getting Started with Relay Modern (20)

Advertisement

More from Nikolas Burk (17)

Recently uploaded (20)

Advertisement

Getting Started with Relay Modern

  1. 1. Nikolas Burk 👋 Developer at Graphcool $ whoami @nikolasburk
  2. 2. Launch Week 🚀 Product Hunt > 1000 upvotesHacker News #1
  3. 3. Getting Started with Relay Modern
  4. 4. 1. Relay - A Brief History 2. Data Fetching 3. Mutations 4. More Features in Relay Modern Agenda @nikolasburk
  5. 5. Relay - A Brief History @nikolasburk
  6. 6. Relay - A Brief History @nikolasburk 01/2015 1st talk about Relay @React.js Conf 2015 2012 FB starts using GraphQL 02/2015 🗣 Announcing Relay will be open-source 08/2015 Relay is open-source 🎉 08/2016 🗣 Announcing plans for “Relay 2” 04/2017 Introducing Relay Modern
  7. 7. GraphQL Clients - homegrown by Facebook - main goal: performance - learning curve - community-driven - main goal: flexibility - easy-to-get-started @nikolasburk
  8. 8. Data Fetching @nikolasburk
  9. 9. Traditional Data Fetching with REST 1. construct & send HTTP request (e.g. with fetch) 2. receive & parse server response 3. store data locally 4. display data in UI 😐 @nikolasburk
  10. 10. Declarative Data Fetching with GraphQL 1. describe data dependencies 2. display data in UI 😍 @nikolasburk
  11. 11. Relay’s core idea is to couple a view component with its data dependencies @nikolasburk
  12. 12. Example: Simple Instagram App @nikolasburk
  13. 13. Post Post ListPage App @nikolasburk
  14. 14. class Post extends React.Component { render () { return ( <div> <img src={this.props.post.imageUrl} /> <div> {this.props.post.description} </div> </div> ) } } export default createFragmentContainer(Post, graphql` fragment Post_post on Post { id description imageUrl } `) Post.js @nikolasburk
  15. 15. class Post extends React.Component { render () { return ( <div> <img src={this.props.post.imageUrl} /> <div> {this.props.post.description} </div> </div> ) } } export default createFragmentContainer(Post, graphql` fragment Post_post on Post { id description imageUrl } `) Post.js @nikolasburk
  16. 16. class Post extends React.Component { render () { return ( <div> <img src={this.props.post.imageUrl} /> <div> {this.props.post.description} </div> </div> ) } } export default createFragmentContainer(Post, graphql` fragment Post_post on Post { id description imageUrl } `) Post.js @nikolasburk
  17. 17. class Post extends React.Component { render () { return ( <div> <img src={this.props.post.imageUrl} /> <div> {this.props.post.description} </div> </div> ) } } export default createFragmentContainer(Post, graphql` fragment Post_post on Post { id description imageUrl } `) Post.js @nikolasburk
  18. 18. class Post extends React.Component { render () { return ( <div> <img src={this.props.post.imageUrl} /> <div> {this.props.post.description} </div> </div> ) } } export default createFragmentContainer(Post, graphql` fragment Post_post on Post { id description imageUrl } `) Post.js @nikolasburk
  19. 19. class Post extends React.Component { render () { return ( <div> <img src={this.props.post.imageUrl} /> <div> {this.props.post.description} </div> </div> ) } } export default createFragmentContainer(Post, graphql` fragment Post_post on Post { id description imageUrl } `) Post.js @nikolasburk
  20. 20. export default createFragmentContainer(ListPage, graphql` fragment ListPage_viewer on Viewer { allPosts @connection(key: “ListPage_allPosts") { edges { node { …Post_post # from Post.js } } } } `) class ListPage extends React.Component { render () { return ( <div> {this.props.viewer.allPosts.edges.map(({node}) => <Post key={node.id} post={node} /> )} </div> ) } } ListPage.js @nikolasburk
  21. 21. export default createFragmentContainer(ListPage, graphql` fragment ListPage_viewer on Viewer { allPosts @connection(key: “ListPage_allPosts") { edges { node { ...Post_post } } } } `) class ListPage extends React.Component { render () { return ( <div> {this.props.viewer.allPosts.edges.map(({node}) => <Post key={node.id} post={node} /> )} </div> ) } } ListPage.js @nikolasburk
  22. 22. export default createFragmentContainer(ListPage, graphql` fragment ListPage_viewer on Viewer { allPosts @connection(key: “ListPage_allPosts") { edges { node { ...Post_post } } } } `) class ListPage extends React.Component { render () { return ( <div> {this.props.viewer.allPosts.edges.map(({node}) => <Post key={node.id} post={node} /> )} </div> ) } } ListPage.js @nikolasburk
  23. 23. export default createFragmentContainer(ListPage, graphql` fragment ListPage_viewer on Viewer { allPosts @connection(key: “ListPage_allPosts") { edges { node { ...Post_post } } } } `) class ListPage extends React.Component { render () { return ( <div> {this.props.viewer.allPosts.edges.map(({node}) => <Post key={node.id} post={node} /> )} </div> ) } } ListPage.js @nikolasburk
  24. 24. export default createFragmentContainer(ListPage, graphql` fragment ListPage_viewer on Viewer { allPosts @connection(key: “ListPage_allPosts") { edges { node { ...Post_post } } } } `) class ListPage extends React.Component { render () { return ( <div> {this.props.viewer.allPosts.edges.map(({node}) => <Post key={node.id} post={node} /> )} </div> ) } } ListPage.js @nikolasburk
  25. 25. export default createFragmentContainer(ListPage, graphql` fragment ListPage_viewer on Viewer { allPosts @connection(key: "ListPage_allPosts") { edges { node { ...Post_post } } } } `) class ListPage extends React.Component { render () { return ( <div> {this.props.viewer.allPosts.edges.map(({node}) => <Post key={node.id} post={node} /> )} </div> ) } } ListPage.js @nikolasburk
  26. 26. The QueryRenderer QueryRenderer is the root of a Relay tree. It takes a query, fetches the data and calls the render callback. @nikolasburk
  27. 27. class App extends Component { render() { return ( <QueryRenderer environment={environment} query={AppAllPostQuery} render={({error, props}) => { if (error) { return <div>{error.message}</div> } else if (props) { return <ListPage viewer={props.viewer} /> } return <div>Loading</div> }} /> ) } } const AppAllPostQuery = graphql` query AppAllPostQuery { viewer { …ListPage_viewer } } ` App.js @nikolasburk
  28. 28. class App extends Component { render() { return ( <QueryRenderer environment={environment} query={AppAllPostQuery} render={({error, props}) => { if (error) { return <div>{error.message}</div> } else if (props) { return <ListPage viewer={props.viewer} /> } return <div>Loading</div> }} /> ) } } const AppAllPostQuery = graphql` query AppAllPostQuery { viewer { …ListPage_viewer } } ` App.js @nikolasburk
  29. 29. class App extends Component { render() { return ( <QueryRenderer environment={environment} query={AppAllPostQuery} render={({error, props}) => { if (error) { return <div>{error.message}</div> } else if (props) { return <ListPage viewer={props.viewer} /> } return <div>Loading</div> }} /> ) } } const AppAllPostQuery = graphql` query AppAllPostQuery { viewer { …ListPage_viewer # from ListPage.js } } ` App.js @nikolasburk
  30. 30. class App extends Component { render() { return ( <QueryRenderer environment={environment} query={AppAllPostQuery} render={({error, props}) => { if (error) { return <div>{error.message}</div> } else if (props) { return <ListPage viewer={props.viewer} /> } return <div>Loading</div> }} /> ) } } const AppAllPostQuery = graphql` query AppAllPostQuery { viewer { …ListPage_viewer } } ` ListPage.js @nikolasburk
  31. 31. class App extends Component { render() { return ( <QueryRenderer environment={environment} query={AppAllPostQuery} render={({error, props}) => { if (error) { return <div>{error.message}</div> } else if (props) { return <ListPage viewer={props.viewer} /> } return <div>Loading</div> }} /> ) } } const AppAllPostQuery = graphql` query AppAllPostQuery { viewer { …ListPage_viewer } } ` ListPage.js @nikolasburk
  32. 32. class App extends Component { render() { return ( <QueryRenderer environment={environment} query={AppAllPostQuery} render={({error, props}) => { if (error) { return <div>{error.message}</div> } else if (props) { return <ListPage viewer={props.viewer} /> } return <div>Loading</div> }} /> ) } } const AppAllPostQuery = graphql` query AppAllPostQuery { viewer { …ListPage_viewer } } ` ListPage.js @nikolasburk
  33. 33. class App extends Component { render() { return ( <QueryRenderer environment={environment} query={AppAllPostQuery} render={({error, props}) => { if (error) { return <div>{error.message}</div> } else if (props) { return <ListPage viewer={props.viewer} /> } return <div>Loading</div> }} /> ) } } const AppAllPostQuery = graphql` query AppAllPostQuery { viewer { …ListPage_viewer } } ` ListPage.js @nikolasburk
  34. 34. Mutations @nikolasburk
  35. 35. Mutations in Relay Modern const {commitMutation} = require('react-relay') commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, }, ) @nikolasburk
  36. 36. Mutations in Relay Modern commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, }, ) @nikolasburk
  37. 37. Mutations in Relay Modern commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, }, ) @nikolasburk
  38. 38. Mutations in Relay Modern commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, }, ) const mutation = graphql` mutation CreatePostMutation($input: CreatePostInput!) { createPost(input: $input) { post { id description imageUrl } } } ` @nikolasburk
  39. 39. Mutations in Relay Modern commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, } ) @nikolasburk
  40. 40. Mutations in Relay Modern commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, }, ) const variables = { input: { description: “Nice Sunset”, imageUrl: “www.example.org/sunset.jpg”, } } @nikolasburk
  41. 41. Mutations in Relay Modern commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, } ) @nikolasburk
  42. 42. Mutations in Relay Modern commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, } ) @nikolasburk
  43. 43. Updating the Cache commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, }, ) updater: (proxyStore) => { const createPostField = proxyStore.getRootField('createPost') const newPost = createPostField.getLinkedRecord('post') const viewerProxy = proxyStore.get(viewerId) const connection = ConnectionHandler.getConnection(viewerProxy, 'ListPage_allPosts') ConnectionHandler.insertEdgeAfter(connection, newPost) } const mutation = graphql` mutation CreatePostMutation($input: CreatePostInput!) { createPost(input: $input) { post { id description imageUrl } } } ` @nikolasburk
  44. 44. Updating the Cache commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, }, ) updater: (proxyStore) => { const createPostField = proxyStore.getRootField('createPost') const newPost = createPostField.getLinkedRecord('post') const viewerProxy = proxyStore.get(viewerId) const connection = ConnectionHandler.getConnection(viewerProxy, 'ListPage_allPosts') ConnectionHandler.insertEdgeAfter(connection, newPost) } const mutation = graphql` mutation CreatePostMutation($input: CreatePostInput!) { createPost(input: $input) { post { id description imageUrl } } } ` @nikolasburk
  45. 45. Updating the Cache commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, }, ) updater: (proxyStore) => { const createPostField = proxyStore.getRootField('createPost') const newPost = createPostField.getLinkedRecord('post') const viewerProxy = proxyStore.get(viewerId) const connection = ConnectionHandler.getConnection(viewerProxy, 'ListPage_allPosts') ConnectionHandler.insertEdgeAfter(connection, newPost) } const mutation = graphql` mutation CreatePostMutation($input: CreatePostInput!) { createPost(input: $input) { post { id description imageUrl } } } ` @nikolasburk
  46. 46. Updating the Cache commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, }, ) updater: (proxyStore) => { const createPostField = proxyStore.getRootField('createPost') const newPost = createPostField.getLinkedRecord('post') const viewerProxy = proxyStore.get(viewerId) const connection = ConnectionHandler.getConnection(viewerProxy, 'ListPage_allPosts') ConnectionHandler.insertEdgeAfter(connection, newPost) } fragment ListPage_viewer on Viewer { allPosts @connection(key: "ListPage_allPosts") { edges { node { ...Post_post } } } } @nikolasburk
  47. 47. Updating the Cache commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, }, ) updater: (proxyStore) => { const createPostField = proxyStore.getRootField('createPost') const newPost = createPostField.getLinkedRecord('post') const viewerProxy = proxyStore.get(viewerId) const connection = ConnectionHandler.getConnection(viewerProxy, 'ListPage_allPosts') ConnectionHandler.insertEdgeAfter(connection, newPost) } fragment ListPage_viewer on Viewer { allPosts @connection(key: "ListPage_allPosts") { edges { node { ...Post_post } } } } @nikolasburk
  48. 48. Mutations in Relay Modern commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, } ) @nikolasburk
  49. 49. Updating the Cache (Optimistically) commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, }, ) optimisticUpdater: (proxyStore) => { const id = 'client:newPost:' + tempID++ const newPost = proxyStore.create(id, 'Post') newPost.setValue(description, 'description') newPost.setValue(imageUrl, 'imageUrl') const viewerProxy = proxyStore.get(viewerId) const connection = ConnectionHandler.getConnection(viewerProxy, 'ListPage_allPosts') ConnectionHandler.insertEdgeAfter(connection, newPost) } @nikolasburk
  50. 50. Updating the Cache (Optimistically) commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, }, ) optimisticUpdater: (proxyStore) => { const id = 'client:newPost:' + tempID++ const newPost = proxyStore.create(id, 'Post') newPost.setValue(description, 'description') newPost.setValue(imageUrl, 'imageUrl') const viewerProxy = proxyStore.get(viewerId) const connection = ConnectionHandler.getConnection(viewerProxy, 'ListPage_allPosts') ConnectionHandler.insertEdgeAfter(connection, newPost) } @nikolasburk
  51. 51. Updating the Cache (Optimistically) commitMutation( environment: Environment, config: { mutation: GraphQLTaggedNode, variables: Variables, onCompleted: (response) => void, onError: (error) => void, updater: (store) => void, optimisticUpdater: (store) => void, }, ) optimisticUpdater: (proxyStore) => { const id = 'client:newPost:' + tempID++ const newPost = proxyStore.create(id, 'Post') newPost.setValue(description, 'description') newPost.setValue(imageUrl, 'imageUrl') const viewerProxy = proxyStore.get(viewerId) const connection = ConnectionHandler.getConnection(viewerProxy, 'ListPage_allPosts') ConnectionHandler.insertEdgeAfter(connection, newPost) } @nikolasburk
  52. 52. More Features in Relay Modern @nikolasburk
  53. 53. The Relay Environment 🌍 ….bundles together the configuration, cache storage, and network-handling that Relay needs in order to operate. const environment = new Environment({ network, store, }) @nikolasburk
  54. 54. GraphQL Subscriptions ⚡ @nikolasburk ….allow to receive realtime events from the server.
  55. 55. Client Schema Extensions 💼 @nikolasburk ….allow to store client state. extend type Post { hasViewerSeen: Boolean }
  56. 56. Garbage Collection 🗑 @nikolasburk … removes objects from memory before the JS Garbage Collector runs.
  57. 57. Compatibility Mode 🎯 @nikolasburk … allows to incrementally update an application from Relay Classic to Relay Modern.
  58. 58. Resources 📚 • Quickstart (Sample Code) https://github.com/graphcool-examples/react-graphql/tree/master/quickstart-with-relay-modern • 1st talk about Relay @ React.JS Conf 2015 (Video) https://www.youtube.com/watch?v=9sc8Pyc51uU • Introducing Relay and GraphQL (Article) https://facebook.github.io/react/blog/2015/02/20/introducing-relay-and-graphql.html • Building Relay Modern (Article) https://wincent.com/blog/relay-modern • Getting Started with Relay Modern (Tutorial) https://www.graph.cool/docs/tutorials/relay-modern-getting-started-woodito7ug/ @nikolasburk
  59. 59. Community 🙌 • slack.graph.cool (> 2000 members) • GraphQL Weekly Newsletter • GraphQL Radio Podcast @nikolasburk
  60. 60. We’re hiring! www.graph.cool/jobs @nikolasburk
  61. 61. Thank you! 🙇 … any questions? @nikolasburk

×