Data-fetching in React applications with Relay & GraphQL

Data-fetching in React applications with Relay & GraphQL

F34d97ba1bfea0ff5e35a9c198562402?s=128

Marc-Andre Giroux

August 10, 2016
Tweet

Transcript

  1. Data-fetching in React applications with Relay & GraphQL 1

  2. A beautiful component 2

  3. A beautiful simple component 3

  4. React { <Shop> <Product> <ProductImage> 4

  5. { Shop component 5

  6. Product component { 6

  7. ProductImage component { 7

  8. What if we needed to add a description? { 8

  9. What kind of data is needed ? Shop Product Image

    9
  10. Let’s fetch that using reusable endpoints ? /shop/1 /products/1 /products/2

    image/sabc images/def 10
  11. Let’s fetch that using ad-hoc endpoints ? /shop_cart_page /shop_cart_page?include=images /shop_cart_page_with_images?num_images=2

    /shop_cart_page_single_prices_and_descriptions_version1.2 /shop_cart_page_with_prices_and_descriptions_but_no_images 11 op_cart_page_with_prices_and_descriptions_and_images_but_only_one_300
  12. 12

  13. GraphQL 13

  14. query { myShop { name } } Simple query 14

  15. Response { “myShop” { “name”: “My Kool Shop” } }

    15
  16. Query { myShop { name location { city address }

    products(orderby: PRICE) { name price } } } 16
  17. Response { “myShop” { “name”: “My Kool Shop”, “location”: {

    “city”: “Montreal”, “address”: “5333 Avenue Casgrain”, }, “products”: [{ “name”: “A Chair”, “price”: 10000 }, { “name”: “A Table”, “price”: 20000 }] } } 17
  18. Type System { myShop { name location { city address

    } products(orderby: PRICE) { name price } } } type QueryRoot { myShop: Shop } 18
  19. Type System enum ProductOrderEnum { PRICE, POPULARITY, ALPHABETICAL } type

    Shop { name: String location: Address products(orderby: OrderEnum): [Product] } { { myShop { name location { city address } products(orderby: POPULARITY) { name price } } } 19
  20. Type System type Address { city: String address: String }

    { { myShop { name location { city address } products(orderby: POPULARITY) { name price } } } 20
  21. Type System type Product { name: String price: Int }

    { { myShop { name location { city address } products(orderby: POPULARITY) { name price } } } 21
  22. Fragments { { myShop { name …locationFragment } } fragment

    locationFragment on Shop { location { city address } } 22
  23. Mutations { mutation { createProduct(name: “Kanye West Shoes”) { name

    } } 23
  24. How Relay can help { Relay React GraphQL 24

  25. Query colocation { query Fragment Fragment Fragment Fragment 25

  26. Query colocation { Shop Product Product Image 26

  27. Relay Containers / Higher Order Components { Relay.createContainer(ShopComponent, { fragments:

    { … } }); Container Shop 27
  28. Shop Component (Relay) { 28

  29. Shop component (Relay) { 29

  30. Product component (Relay) { 30

  31. ProductImage component (Relay) { 31

  32. How the *&^#@$ does that even work? { 32

  33. Step 1: Making sense out of fragments { fragments: {

    image: () => Relay.QL` fragment on Image { url } `, }, 33
  34. Relay.QL (pre-transform) { fragments: { image: () => Relay.QL` fragment

    on Image { url } `, }, 34
  35. Relay.QL (transformed) { fragments: { image: function image() { return

    function () { return { children: [{ fieldName: 'url', kind: 'Field', metadata: {}, type: 'String' }, { fieldName: 'id', kind: 'Field', metadata: { isGenerated: true, isRequisite: true }, type: 'ID' }], id: _reactRelay2.default.QL.__id(), kind: 'Fragment', metadata: {}, name: 'ProductImage_ImageRelayQL', type: 'Image' }; }(); } 35
  36. Step 2: Query diff ( The Store ) { RelayRecord

    Store • Client Side Cache • Normalized / Flattened Store 36
  37. Step 2: Query diff { fragments: { product: () =>

    Relay.QL` fragment on Product { name image { url } } `, }, 37
  38. Step 2: Query diff { fragments: { product: () =>

    Relay.QL` fragment on Product { name description image { url } } `, }, 38
  39. Step 2: Query diff { fragments: { product: () =>

    Relay.QL` fragment on Product { description } `, }, 39
  40. Step 2: Query diff { fragments: { product: () =>

    Relay.QL` fragment on Product { description } `, }, 40
  41. Step 3: Split Deferred queries { fragments: { product: ()

    => Relay.QL` fragment on Product { name description ${Images.getFragment('product').defer()}} } `, }, 41
  42. Step 3: Split Deferred queries { 42

  43. Step 3: Split Deferred queries { 43

  44. Step 4: Subtract in-flight queries { 44

  45. Step 4: Subtract in-flight queries { 45

  46. { myShop { name location { city address } products(orderby:

    PRICE) { name price } } } Final step: Printing { 46
  47. Back to the Store { 47 Relay Record Store Cached

    Records Queued Records
  48. Mutations { class AddProductMutation extends Relay.Mutation { getMutation() { return

    Relay.QL`mutation { addProduct }`; } getVariables() { return { productName: this.props.product.name }; } getFatQuery() { … } getConfigs() { … } getOptimisticResponse() { … } } 48
  49. And so much more { 49 Subscriptions @stream Garbage collection

    Server side rendering Connections
  50. For more info: { 50 https://facebook.github.io/relay https://github.com/facebook/graphql

  51. Thank you! Try it out yourself :) @__xuorig__ http://mgiroux.me xuorig

    51