Slide 1

Slide 1 text

Data-fetching in React applications with Relay & GraphQL 1

Slide 2

Slide 2 text

A beautiful component 2

Slide 3

Slide 3 text

A beautiful simple component 3

Slide 4

Slide 4 text

React { 4

Slide 5

Slide 5 text

{ Shop component 5

Slide 6

Slide 6 text

Product component { 6

Slide 7

Slide 7 text

ProductImage component { 7

Slide 8

Slide 8 text

What if we needed to add a description? { 8

Slide 9

Slide 9 text

What kind of data is needed ? Shop Product Image 9

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

12

Slide 13

Slide 13 text

GraphQL 13

Slide 14

Slide 14 text

query { myShop { name } } Simple query 14

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

How Relay can help { Relay React GraphQL 24

Slide 25

Slide 25 text

Query colocation { query Fragment Fragment Fragment Fragment 25

Slide 26

Slide 26 text

Query colocation { Shop Product Product Image 26

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

Shop Component (Relay) { 28

Slide 29

Slide 29 text

Shop component (Relay) { 29

Slide 30

Slide 30 text

Product component (Relay) { 30

Slide 31

Slide 31 text

ProductImage component (Relay) { 31

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

Step 3: Split Deferred queries { 42

Slide 43

Slide 43 text

Step 3: Split Deferred queries { 43

Slide 44

Slide 44 text

Step 4: Subtract in-flight queries { 44

Slide 45

Slide 45 text

Step 4: Subtract in-flight queries { 45

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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