Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Data-fetching in React applications with Relay & GraphQL

Data-fetching in React applications with Relay & GraphQL

Marc-Andre Giroux

August 10, 2016
Tweet

More Decks by Marc-Andre Giroux

Other Decks in Programming

Transcript

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

    View Slide

  2. A beautiful component
    2

    View Slide

  3. A beautiful simple component
    3

    View Slide

  4. React
    {



    4

    View Slide

  5. {
    Shop component
    5

    View Slide

  6. Product component
    {
    6

    View Slide

  7. ProductImage component
    {
    7

    View Slide

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

    View Slide

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

    View Slide

  10. Let’s fetch that using reusable endpoints ?
    /shop/1
    /products/1
    /products/2
    image/sabc
    images/def
    10

    View Slide

  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

    View Slide

  12. 12

    View Slide

  13. GraphQL
    13

    View Slide

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

    View Slide

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

    View Slide

  16. Query
    {
    myShop {
    name
    location {
    city
    address
    }
    products(orderby: PRICE) {
    name
    price
    }
    }
    }
    16

    View Slide

  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

    View Slide

  18. Type System
    {
    myShop {
    name
    location {
    city
    address
    }
    products(orderby: PRICE) {
    name
    price
    }
    }
    }
    type QueryRoot {
    myShop: Shop
    }
    18

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  22. Fragments
    {
    {
    myShop {
    name
    …locationFragment
    }
    }
    fragment locationFragment on Shop {
    location {
    city
    address
    }
    }
    22

    View Slide

  23. Mutations
    {
    mutation {
    createProduct(name: “Kanye West Shoes”) {
    name
    }
    }
    23

    View Slide

  24. How Relay can help
    {
    Relay
    React GraphQL
    24

    View Slide

  25. Query colocation
    {
    query
    Fragment
    Fragment
    Fragment Fragment
    25

    View Slide

  26. Query colocation
    {
    Shop
    Product
    Product
    Image
    26

    View Slide

  27. Relay Containers / Higher Order Components
    {
    Relay.createContainer(ShopComponent, {
    fragments: { … }
    });
    Container
    Shop
    27

    View Slide

  28. Shop Component (Relay)
    {
    28

    View Slide

  29. Shop component (Relay)
    {
    29

    View Slide

  30. Product component (Relay)
    {
    30

    View Slide

  31. ProductImage component (Relay)
    {
    31

    View Slide

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

    View Slide

  33. Step 1: Making sense out of fragments
    {
    fragments: {
    image: () => Relay.QL`
    fragment on Image {
    url
    }
    `,
    },
    33

    View Slide

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

    View Slide

  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

    View Slide

  36. Step 2: Query diff ( The Store )
    {
    RelayRecord
    Store
    • Client Side Cache
    • Normalized / Flattened Store
    36

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  42. Step 3: Split Deferred queries
    {
    42

    View Slide

  43. Step 3: Split Deferred queries
    {
    43

    View Slide

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

    View Slide

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

    View Slide

  46. {
    myShop {
    name
    location {
    city
    address
    }
    products(orderby: PRICE) {
    name
    price
    }
    }
    }
    Final step: Printing
    {
    46

    View Slide

  47. Back to the Store
    {
    47
    Relay Record
    Store
    Cached
    Records
    Queued
    Records

    View Slide

  48. Mutations
    {
    class AddProductMutation extends Relay.Mutation {
    getMutation() {
    return Relay.QL`mutation { addProduct }`;
    }
    getVariables() {
    return { productName: this.props.product.name };
    }
    getFatQuery() { … }
    getConfigs() { … }
    getOptimisticResponse() { … }
    }
    48

    View Slide

  49. And so much more
    {
    49
    Subscriptions
    @stream
    Garbage collection
    Server side rendering
    Connections

    View Slide

  50. For more info:
    {
    50
    https://facebook.github.io/relay
    https://github.com/facebook/graphql

    View Slide

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

    View Slide