SlideShare a Scribd company logo
1 of 63
Download to read offline
Nikolas Burk 👋
Developer at Graphcool
$ whoami
@nikolasburk
Launch Week 🚀
Product Hunt > 1000 upvotesHacker News #1
Getting Started with
Relay Modern
1. Relay - A Brief History
2. Data Fetching
3. Mutations
4. More Features in Relay Modern
Agenda
@nikolasburk
Relay - A Brief History
@nikolasburk
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
GraphQL Clients
- homegrown by Facebook
- main goal: performance
- learning curve
- community-driven
- main goal: flexibility
- easy-to-get-started
@nikolasburk
Data Fetching
@nikolasburk
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
Declarative Data Fetching with GraphQL
1. describe data dependencies
2. display data in UI
😍
@nikolasburk
Relay’s core idea is to couple a view
component with its data dependencies
@nikolasburk
Example:
Simple Instagram App
@nikolasburk
Post Post
ListPage
App
@nikolasburk
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
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
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
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
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
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
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
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
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
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
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
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
The QueryRenderer
QueryRenderer is the root of a Relay tree.
It takes a query, fetches the data
and calls the render callback.
@nikolasburk
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
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
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
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
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
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
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
Mutations
@nikolasburk
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
More Features in Relay Modern
@nikolasburk
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
GraphQL Subscriptions ⚡
@nikolasburk
….allow to receive realtime events from the server.
Client Schema Extensions 💼
@nikolasburk
….allow to store client state.
extend type Post {
hasViewerSeen: Boolean
}
Garbage Collection 🗑
@nikolasburk
… removes objects from memory before the
JS Garbage Collector runs.
Compatibility Mode 🎯
@nikolasburk
… allows to incrementally update an application
from Relay Classic to Relay Modern.
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
Community 🙌
• slack.graph.cool (> 2000 members)
• GraphQL Weekly Newsletter
• GraphQL Radio Podcast
@nikolasburk
We’re hiring!
www.graph.cool/jobs
@nikolasburk
Thank you! 🙇
… any questions?
@nikolasburk

More Related Content

What's hot

Migrating Airflow-based Apache Spark Jobs to Kubernetes – the Native Way
Migrating Airflow-based Apache Spark Jobs to Kubernetes – the Native WayMigrating Airflow-based Apache Spark Jobs to Kubernetes – the Native Way
Migrating Airflow-based Apache Spark Jobs to Kubernetes – the Native WayDatabricks
 
Solutions for bi-directional integration between Oracle RDBMS & Apache Kafka
Solutions for bi-directional integration between Oracle RDBMS & Apache KafkaSolutions for bi-directional integration between Oracle RDBMS & Apache Kafka
Solutions for bi-directional integration between Oracle RDBMS & Apache KafkaGuido Schmutz
 
Event sourcing - what could possibly go wrong ? Devoxx PL 2021
Event sourcing  - what could possibly go wrong ? Devoxx PL 2021Event sourcing  - what could possibly go wrong ? Devoxx PL 2021
Event sourcing - what could possibly go wrong ? Devoxx PL 2021Andrzej Ludwikowski
 
Data all over the place! How SQL and Apache Calcite bring sanity to streaming...
Data all over the place! How SQL and Apache Calcite bring sanity to streaming...Data all over the place! How SQL and Apache Calcite bring sanity to streaming...
Data all over the place! How SQL and Apache Calcite bring sanity to streaming...Julian Hyde
 
Extending Apache Spark – Beyond Spark Session Extensions
Extending Apache Spark – Beyond Spark Session ExtensionsExtending Apache Spark – Beyond Spark Session Extensions
Extending Apache Spark – Beyond Spark Session ExtensionsDatabricks
 
Flink Forward SF 2017: David Hardwick, Sean Hester & David Brelloch - Dynami...
Flink Forward SF 2017: David Hardwick, Sean Hester & David Brelloch -  Dynami...Flink Forward SF 2017: David Hardwick, Sean Hester & David Brelloch -  Dynami...
Flink Forward SF 2017: David Hardwick, Sean Hester & David Brelloch - Dynami...Flink Forward
 
Deep dive into stateful stream processing in structured streaming by Tathaga...
Deep dive into stateful stream processing in structured streaming  by Tathaga...Deep dive into stateful stream processing in structured streaming  by Tathaga...
Deep dive into stateful stream processing in structured streaming by Tathaga...Databricks
 
Interactive Kafka Streams
Interactive Kafka StreamsInteractive Kafka Streams
Interactive Kafka Streamsconfluent
 
Samza 0.13 meetup slide v1.0.pptx
Samza 0.13 meetup slide   v1.0.pptxSamza 0.13 meetup slide   v1.0.pptx
Samza 0.13 meetup slide v1.0.pptxYi Pan
 
Solutions for bi-directional integration between Oracle RDBMS and Apache Kafka
Solutions for bi-directional integration between Oracle RDBMS and Apache KafkaSolutions for bi-directional integration between Oracle RDBMS and Apache Kafka
Solutions for bi-directional integration between Oracle RDBMS and Apache KafkaGuido Schmutz
 
A Deep Dive into Stateful Stream Processing in Structured Streaming with Tath...
A Deep Dive into Stateful Stream Processing in Structured Streaming with Tath...A Deep Dive into Stateful Stream Processing in Structured Streaming with Tath...
A Deep Dive into Stateful Stream Processing in Structured Streaming with Tath...Databricks
 
Component level caching with react
Component level caching with reactComponent level caching with react
Component level caching with reactAnusheelSingh2
 
Performance Analysis and Optimizations for Kafka Streams Applications
Performance Analysis and Optimizations for Kafka Streams ApplicationsPerformance Analysis and Optimizations for Kafka Streams Applications
Performance Analysis and Optimizations for Kafka Streams ApplicationsGuozhang Wang
 
Distributed Real-Time Stream Processing: Why and How 2.0
Distributed Real-Time Stream Processing:  Why and How 2.0Distributed Real-Time Stream Processing:  Why and How 2.0
Distributed Real-Time Stream Processing: Why and How 2.0Petr Zapletal
 
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and Typescript
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and TypescriptMongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and Typescript
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and TypescriptMongoDB
 
Deep Dive into Stateful Stream Processing in Structured Streaming with Tathag...
Deep Dive into Stateful Stream Processing in Structured Streaming with Tathag...Deep Dive into Stateful Stream Processing in Structured Streaming with Tathag...
Deep Dive into Stateful Stream Processing in Structured Streaming with Tathag...Databricks
 
User Defined Aggregation in Apache Spark: A Love Story
User Defined Aggregation in Apache Spark: A Love StoryUser Defined Aggregation in Apache Spark: A Love Story
User Defined Aggregation in Apache Spark: A Love StoryDatabricks
 

What's hot (18)

Ajax
AjaxAjax
Ajax
 
Migrating Airflow-based Apache Spark Jobs to Kubernetes – the Native Way
Migrating Airflow-based Apache Spark Jobs to Kubernetes – the Native WayMigrating Airflow-based Apache Spark Jobs to Kubernetes – the Native Way
Migrating Airflow-based Apache Spark Jobs to Kubernetes – the Native Way
 
Solutions for bi-directional integration between Oracle RDBMS & Apache Kafka
Solutions for bi-directional integration between Oracle RDBMS & Apache KafkaSolutions for bi-directional integration between Oracle RDBMS & Apache Kafka
Solutions for bi-directional integration between Oracle RDBMS & Apache Kafka
 
Event sourcing - what could possibly go wrong ? Devoxx PL 2021
Event sourcing  - what could possibly go wrong ? Devoxx PL 2021Event sourcing  - what could possibly go wrong ? Devoxx PL 2021
Event sourcing - what could possibly go wrong ? Devoxx PL 2021
 
Data all over the place! How SQL and Apache Calcite bring sanity to streaming...
Data all over the place! How SQL and Apache Calcite bring sanity to streaming...Data all over the place! How SQL and Apache Calcite bring sanity to streaming...
Data all over the place! How SQL and Apache Calcite bring sanity to streaming...
 
Extending Apache Spark – Beyond Spark Session Extensions
Extending Apache Spark – Beyond Spark Session ExtensionsExtending Apache Spark – Beyond Spark Session Extensions
Extending Apache Spark – Beyond Spark Session Extensions
 
Flink Forward SF 2017: David Hardwick, Sean Hester & David Brelloch - Dynami...
Flink Forward SF 2017: David Hardwick, Sean Hester & David Brelloch -  Dynami...Flink Forward SF 2017: David Hardwick, Sean Hester & David Brelloch -  Dynami...
Flink Forward SF 2017: David Hardwick, Sean Hester & David Brelloch - Dynami...
 
Deep dive into stateful stream processing in structured streaming by Tathaga...
Deep dive into stateful stream processing in structured streaming  by Tathaga...Deep dive into stateful stream processing in structured streaming  by Tathaga...
Deep dive into stateful stream processing in structured streaming by Tathaga...
 
Interactive Kafka Streams
Interactive Kafka StreamsInteractive Kafka Streams
Interactive Kafka Streams
 
Samza 0.13 meetup slide v1.0.pptx
Samza 0.13 meetup slide   v1.0.pptxSamza 0.13 meetup slide   v1.0.pptx
Samza 0.13 meetup slide v1.0.pptx
 
Solutions for bi-directional integration between Oracle RDBMS and Apache Kafka
Solutions for bi-directional integration between Oracle RDBMS and Apache KafkaSolutions for bi-directional integration between Oracle RDBMS and Apache Kafka
Solutions for bi-directional integration between Oracle RDBMS and Apache Kafka
 
A Deep Dive into Stateful Stream Processing in Structured Streaming with Tath...
A Deep Dive into Stateful Stream Processing in Structured Streaming with Tath...A Deep Dive into Stateful Stream Processing in Structured Streaming with Tath...
A Deep Dive into Stateful Stream Processing in Structured Streaming with Tath...
 
Component level caching with react
Component level caching with reactComponent level caching with react
Component level caching with react
 
Performance Analysis and Optimizations for Kafka Streams Applications
Performance Analysis and Optimizations for Kafka Streams ApplicationsPerformance Analysis and Optimizations for Kafka Streams Applications
Performance Analysis and Optimizations for Kafka Streams Applications
 
Distributed Real-Time Stream Processing: Why and How 2.0
Distributed Real-Time Stream Processing:  Why and How 2.0Distributed Real-Time Stream Processing:  Why and How 2.0
Distributed Real-Time Stream Processing: Why and How 2.0
 
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and Typescript
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and TypescriptMongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and Typescript
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and Typescript
 
Deep Dive into Stateful Stream Processing in Structured Streaming with Tathag...
Deep Dive into Stateful Stream Processing in Structured Streaming with Tathag...Deep Dive into Stateful Stream Processing in Structured Streaming with Tathag...
Deep Dive into Stateful Stream Processing in Structured Streaming with Tathag...
 
User Defined Aggregation in Apache Spark: A Love Story
User Defined Aggregation in Apache Spark: A Love StoryUser Defined Aggregation in Apache Spark: A Love Story
User Defined Aggregation in Apache Spark: A Love Story
 

Similar to Getting Started with Relay Modern

Building Universal Web Apps with React ForwardJS 2017
Building Universal Web Apps with React ForwardJS 2017Building Universal Web Apps with React ForwardJS 2017
Building Universal Web Apps with React ForwardJS 2017Elyse Kolker Gordon
 
2018 05-16 Evolving Technologies: React, Babel & Webpack
2018 05-16 Evolving Technologies: React, Babel & Webpack2018 05-16 Evolving Technologies: React, Babel & Webpack
2018 05-16 Evolving Technologies: React, Babel & WebpackCodifly
 
Learning React: Facebook's Javascript Library For Building User Interfaces
Learning React: Facebook's Javascript Library For Building User InterfacesLearning React: Facebook's Javascript Library For Building User Interfaces
Learning React: Facebook's Javascript Library For Building User InterfacesKen Wheeler
 
Crossing platforms with JavaScript & React
Crossing platforms with JavaScript & React Crossing platforms with JavaScript & React
Crossing platforms with JavaScript & React Robert DeLuca
 
React + Redux Introduction
React + Redux IntroductionReact + Redux Introduction
React + Redux IntroductionNikolaus Graf
 
Flask and Angular: An approach to build robust platforms
Flask and Angular:  An approach to build robust platformsFlask and Angular:  An approach to build robust platforms
Flask and Angular: An approach to build robust platformsAyush Sharma
 
SharePoint Conference 2018 - APIs, APIs everywhere!
SharePoint Conference 2018 - APIs, APIs everywhere!SharePoint Conference 2018 - APIs, APIs everywhere!
SharePoint Conference 2018 - APIs, APIs everywhere!Sébastien Levert
 
Universal JS Web Applications with React - Web Summer Camp 2017, Rovinj (Work...
Universal JS Web Applications with React - Web Summer Camp 2017, Rovinj (Work...Universal JS Web Applications with React - Web Summer Camp 2017, Rovinj (Work...
Universal JS Web Applications with React - Web Summer Camp 2017, Rovinj (Work...Luciano Mammino
 
React on Rails - RailsConf 2017 (Phoenix)
 React on Rails - RailsConf 2017 (Phoenix) React on Rails - RailsConf 2017 (Phoenix)
React on Rails - RailsConf 2017 (Phoenix)Jo Cranford
 
React.js: You deserve to know about it
React.js: You deserve to know about itReact.js: You deserve to know about it
React.js: You deserve to know about itAnderson Aguiar
 
Dive into React Performance
Dive into React PerformanceDive into React Performance
Dive into React PerformanceChing Ting Wu
 
How Bitbucket Pipelines Loads Connect UI Assets Super-fast
How Bitbucket Pipelines Loads Connect UI Assets Super-fastHow Bitbucket Pipelines Loads Connect UI Assets Super-fast
How Bitbucket Pipelines Loads Connect UI Assets Super-fastAtlassian
 
React table tutorial project setup, use table, and usefilter
React table tutorial project setup, use table, and usefilterReact table tutorial project setup, use table, and usefilter
React table tutorial project setup, use table, and usefilterKaty Slemon
 
Big Data processing with Spark, Scala or Java?
Big Data processing with Spark, Scala or Java?Big Data processing with Spark, Scala or Java?
Big Data processing with Spark, Scala or Java?Erik-Berndt Scheper
 
Office 365 Groups and Tasks API - Getting Started
Office 365 Groups and Tasks API - Getting StartedOffice 365 Groups and Tasks API - Getting Started
Office 365 Groups and Tasks API - Getting StartedDragan Panjkov
 
Time to React!
Time to React!Time to React!
Time to React!STX Next
 

Similar to Getting Started with Relay Modern (20)

React js
React jsReact js
React js
 
React 101
React 101React 101
React 101
 
Building Universal Web Apps with React ForwardJS 2017
Building Universal Web Apps with React ForwardJS 2017Building Universal Web Apps with React ForwardJS 2017
Building Universal Web Apps with React ForwardJS 2017
 
2018 05-16 Evolving Technologies: React, Babel & Webpack
2018 05-16 Evolving Technologies: React, Babel & Webpack2018 05-16 Evolving Technologies: React, Babel & Webpack
2018 05-16 Evolving Technologies: React, Babel & Webpack
 
Learning React: Facebook's Javascript Library For Building User Interfaces
Learning React: Facebook's Javascript Library For Building User InterfacesLearning React: Facebook's Javascript Library For Building User Interfaces
Learning React: Facebook's Javascript Library For Building User Interfaces
 
Crossing platforms with JavaScript & React
Crossing platforms with JavaScript & React Crossing platforms with JavaScript & React
Crossing platforms with JavaScript & React
 
React + Redux Introduction
React + Redux IntroductionReact + Redux Introduction
React + Redux Introduction
 
Flask and Angular: An approach to build robust platforms
Flask and Angular:  An approach to build robust platformsFlask and Angular:  An approach to build robust platforms
Flask and Angular: An approach to build robust platforms
 
SharePoint Conference 2018 - APIs, APIs everywhere!
SharePoint Conference 2018 - APIs, APIs everywhere!SharePoint Conference 2018 - APIs, APIs everywhere!
SharePoint Conference 2018 - APIs, APIs everywhere!
 
React lecture
React lectureReact lecture
React lecture
 
Universal JS Web Applications with React - Web Summer Camp 2017, Rovinj (Work...
Universal JS Web Applications with React - Web Summer Camp 2017, Rovinj (Work...Universal JS Web Applications with React - Web Summer Camp 2017, Rovinj (Work...
Universal JS Web Applications with React - Web Summer Camp 2017, Rovinj (Work...
 
React on Rails - RailsConf 2017 (Phoenix)
 React on Rails - RailsConf 2017 (Phoenix) React on Rails - RailsConf 2017 (Phoenix)
React on Rails - RailsConf 2017 (Phoenix)
 
React.js: You deserve to know about it
React.js: You deserve to know about itReact.js: You deserve to know about it
React.js: You deserve to know about it
 
Advanced redux
Advanced reduxAdvanced redux
Advanced redux
 
Dive into React Performance
Dive into React PerformanceDive into React Performance
Dive into React Performance
 
How Bitbucket Pipelines Loads Connect UI Assets Super-fast
How Bitbucket Pipelines Loads Connect UI Assets Super-fastHow Bitbucket Pipelines Loads Connect UI Assets Super-fast
How Bitbucket Pipelines Loads Connect UI Assets Super-fast
 
React table tutorial project setup, use table, and usefilter
React table tutorial project setup, use table, and usefilterReact table tutorial project setup, use table, and usefilter
React table tutorial project setup, use table, and usefilter
 
Big Data processing with Spark, Scala or Java?
Big Data processing with Spark, Scala or Java?Big Data processing with Spark, Scala or Java?
Big Data processing with Spark, Scala or Java?
 
Office 365 Groups and Tasks API - Getting Started
Office 365 Groups and Tasks API - Getting StartedOffice 365 Groups and Tasks API - Getting Started
Office 365 Groups and Tasks API - Getting Started
 
Time to React!
Time to React!Time to React!
Time to React!
 

More from Nikolas Burk

Next-generation API Development with GraphQL and Prisma
Next-generation API Development with GraphQL and PrismaNext-generation API Development with GraphQL and Prisma
Next-generation API Development with GraphQL and PrismaNikolas Burk
 
Code-first GraphQL Server Development with Prisma
Code-first  GraphQL Server Development with PrismaCode-first  GraphQL Server Development with Prisma
Code-first GraphQL Server Development with PrismaNikolas Burk
 
GraphQL & Prisma from Scratch
GraphQL & Prisma from ScratchGraphQL & Prisma from Scratch
GraphQL & Prisma from ScratchNikolas Burk
 
GraphQL Schema Stitching with Prisma & Contentful
GraphQL Schema Stitching with Prisma & ContentfulGraphQL Schema Stitching with Prisma & Contentful
GraphQL Schema Stitching with Prisma & ContentfulNikolas Burk
 
Managing GraphQL servers with AWS Fargate & Prisma Cloud
Managing GraphQL servers  with AWS Fargate & Prisma CloudManaging GraphQL servers  with AWS Fargate & Prisma Cloud
Managing GraphQL servers with AWS Fargate & Prisma CloudNikolas Burk
 
Building GraphQL Servers with Node.JS & Prisma
Building GraphQL Servers with Node.JS & PrismaBuilding GraphQL Servers with Node.JS & Prisma
Building GraphQL Servers with Node.JS & PrismaNikolas Burk
 
The GraphQL Ecosystem in 2018
The GraphQL Ecosystem in 2018The GraphQL Ecosystem in 2018
The GraphQL Ecosystem in 2018Nikolas Burk
 
Building Serverless GraphQL Backends
Building Serverless GraphQL BackendsBuilding Serverless GraphQL Backends
Building Serverless GraphQL BackendsNikolas Burk
 
GraphQL Subscriptions
GraphQL SubscriptionsGraphQL Subscriptions
GraphQL SubscriptionsNikolas Burk
 
The Serverless GraphQL Backend Architecture
The Serverless GraphQL Backend ArchitectureThe Serverless GraphQL Backend Architecture
The Serverless GraphQL Backend ArchitectureNikolas Burk
 
State Management & Unidirectional Data Flow
State Management & Unidirectional Data FlowState Management & Unidirectional Data Flow
State Management & Unidirectional Data FlowNikolas Burk
 
Diving into GraphQL, React & Apollo
Diving into GraphQL, React & ApolloDiving into GraphQL, React & Apollo
Diving into GraphQL, React & ApolloNikolas Burk
 
Authentication, Authorization & Error Handling with GraphQL
Authentication, Authorization & Error Handling with GraphQLAuthentication, Authorization & Error Handling with GraphQL
Authentication, Authorization & Error Handling with GraphQLNikolas Burk
 
Building a Realtime Chat with React Native (Expo) & GraphQL Subscriptions
Building a Realtime Chat with React Native (Expo) & GraphQL Subscriptions Building a Realtime Chat with React Native (Expo) & GraphQL Subscriptions
Building a Realtime Chat with React Native (Expo) & GraphQL Subscriptions Nikolas Burk
 
Building a Realtime Chat with React & GraphQL Subscriptions
Building a Realtime Chat with React & GraphQL Subscriptions Building a Realtime Chat with React & GraphQL Subscriptions
Building a Realtime Chat with React & GraphQL Subscriptions Nikolas Burk
 
REST in Peace - Using GraphQL with Apollo on iOS
REST in Peace - Using GraphQL with Apollo on iOSREST in Peace - Using GraphQL with Apollo on iOS
REST in Peace - Using GraphQL with Apollo on iOSNikolas Burk
 

More from Nikolas Burk (17)

Next-generation API Development with GraphQL and Prisma
Next-generation API Development with GraphQL and PrismaNext-generation API Development with GraphQL and Prisma
Next-generation API Development with GraphQL and Prisma
 
Code-first GraphQL Server Development with Prisma
Code-first  GraphQL Server Development with PrismaCode-first  GraphQL Server Development with Prisma
Code-first GraphQL Server Development with Prisma
 
GraphQL & Prisma from Scratch
GraphQL & Prisma from ScratchGraphQL & Prisma from Scratch
GraphQL & Prisma from Scratch
 
GraphQL Schema Stitching with Prisma & Contentful
GraphQL Schema Stitching with Prisma & ContentfulGraphQL Schema Stitching with Prisma & Contentful
GraphQL Schema Stitching with Prisma & Contentful
 
Managing GraphQL servers with AWS Fargate & Prisma Cloud
Managing GraphQL servers  with AWS Fargate & Prisma CloudManaging GraphQL servers  with AWS Fargate & Prisma Cloud
Managing GraphQL servers with AWS Fargate & Prisma Cloud
 
Building GraphQL Servers with Node.JS & Prisma
Building GraphQL Servers with Node.JS & PrismaBuilding GraphQL Servers with Node.JS & Prisma
Building GraphQL Servers with Node.JS & Prisma
 
The GraphQL Ecosystem in 2018
The GraphQL Ecosystem in 2018The GraphQL Ecosystem in 2018
The GraphQL Ecosystem in 2018
 
React & GraphQL
React & GraphQLReact & GraphQL
React & GraphQL
 
Building Serverless GraphQL Backends
Building Serverless GraphQL BackendsBuilding Serverless GraphQL Backends
Building Serverless GraphQL Backends
 
GraphQL Subscriptions
GraphQL SubscriptionsGraphQL Subscriptions
GraphQL Subscriptions
 
The Serverless GraphQL Backend Architecture
The Serverless GraphQL Backend ArchitectureThe Serverless GraphQL Backend Architecture
The Serverless GraphQL Backend Architecture
 
State Management & Unidirectional Data Flow
State Management & Unidirectional Data FlowState Management & Unidirectional Data Flow
State Management & Unidirectional Data Flow
 
Diving into GraphQL, React & Apollo
Diving into GraphQL, React & ApolloDiving into GraphQL, React & Apollo
Diving into GraphQL, React & Apollo
 
Authentication, Authorization & Error Handling with GraphQL
Authentication, Authorization & Error Handling with GraphQLAuthentication, Authorization & Error Handling with GraphQL
Authentication, Authorization & Error Handling with GraphQL
 
Building a Realtime Chat with React Native (Expo) & GraphQL Subscriptions
Building a Realtime Chat with React Native (Expo) & GraphQL Subscriptions Building a Realtime Chat with React Native (Expo) & GraphQL Subscriptions
Building a Realtime Chat with React Native (Expo) & GraphQL Subscriptions
 
Building a Realtime Chat with React & GraphQL Subscriptions
Building a Realtime Chat with React & GraphQL Subscriptions Building a Realtime Chat with React & GraphQL Subscriptions
Building a Realtime Chat with React & GraphQL Subscriptions
 
REST in Peace - Using GraphQL with Apollo on iOS
REST in Peace - Using GraphQL with Apollo on iOSREST in Peace - Using GraphQL with Apollo on iOS
REST in Peace - Using GraphQL with Apollo on iOS
 

Recently uploaded

Rapidoform for Modern Form Building and Insights
Rapidoform for Modern Form Building and InsightsRapidoform for Modern Form Building and Insights
Rapidoform for Modern Form Building and Insightsrapidoform
 
architecting-ai-in-the-enterprise-apis-and-applications.pdf
architecting-ai-in-the-enterprise-apis-and-applications.pdfarchitecting-ai-in-the-enterprise-apis-and-applications.pdf
architecting-ai-in-the-enterprise-apis-and-applications.pdfWSO2
 
Spring into AI presented by Dan Vega 5/14
Spring into AI presented by Dan Vega 5/14Spring into AI presented by Dan Vega 5/14
Spring into AI presented by Dan Vega 5/14VMware Tanzu
 
Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024Andreas Granig
 
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...Lisi Hocke
 
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-CloudAlluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-CloudAlluxio, Inc.
 
Jax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined DeckJax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined DeckMarc Lester
 
[GeeCON2024] How I learned to stop worrying and love the dark silicon apocalypse
[GeeCON2024] How I learned to stop worrying and love the dark silicon apocalypse[GeeCON2024] How I learned to stop worrying and love the dark silicon apocalypse
[GeeCON2024] How I learned to stop worrying and love the dark silicon apocalypseTomasz Kowalczewski
 
Navigation in flutter – how to add stack, tab, and drawer navigators to your ...
Navigation in flutter – how to add stack, tab, and drawer navigators to your ...Navigation in flutter – how to add stack, tab, and drawer navigators to your ...
Navigation in flutter – how to add stack, tab, and drawer navigators to your ...Flutter Agency
 
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024MulesoftMunichMeetup
 
Microsoft365_Dev_Security_2024_05_16.pdf
Microsoft365_Dev_Security_2024_05_16.pdfMicrosoft365_Dev_Security_2024_05_16.pdf
Microsoft365_Dev_Security_2024_05_16.pdfMarkus Moeller
 
OpenChain Webinar: AboutCode and Beyond - End-to-End SCA
OpenChain Webinar: AboutCode and Beyond - End-to-End SCAOpenChain Webinar: AboutCode and Beyond - End-to-End SCA
OpenChain Webinar: AboutCode and Beyond - End-to-End SCAShane Coughlan
 
BusinessGPT - Security and Governance for Generative AI
BusinessGPT  - Security and Governance for Generative AIBusinessGPT  - Security and Governance for Generative AI
BusinessGPT - Security and Governance for Generative AIAGATSoftware
 
GraphSummit Milan - Visione e roadmap del prodotto Neo4j
GraphSummit Milan - Visione e roadmap del prodotto Neo4jGraphSummit Milan - Visione e roadmap del prodotto Neo4j
GraphSummit Milan - Visione e roadmap del prodotto Neo4jNeo4j
 
A Deep Dive into Secure Product Development Frameworks.pdf
A Deep Dive into Secure Product Development Frameworks.pdfA Deep Dive into Secure Product Development Frameworks.pdf
A Deep Dive into Secure Product Development Frameworks.pdfICS
 
GraphSummit Milan - Neo4j: The Art of the Possible with Graph
GraphSummit Milan - Neo4j: The Art of the Possible with GraphGraphSummit Milan - Neo4j: The Art of the Possible with Graph
GraphSummit Milan - Neo4j: The Art of the Possible with GraphNeo4j
 
Transformer Neural Network Use Cases with Links
Transformer Neural Network Use Cases with LinksTransformer Neural Network Use Cases with Links
Transformer Neural Network Use Cases with LinksJinanKordab
 

Recently uploaded (20)

Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
 
Rapidoform for Modern Form Building and Insights
Rapidoform for Modern Form Building and InsightsRapidoform for Modern Form Building and Insights
Rapidoform for Modern Form Building and Insights
 
architecting-ai-in-the-enterprise-apis-and-applications.pdf
architecting-ai-in-the-enterprise-apis-and-applications.pdfarchitecting-ai-in-the-enterprise-apis-and-applications.pdf
architecting-ai-in-the-enterprise-apis-and-applications.pdf
 
Spring into AI presented by Dan Vega 5/14
Spring into AI presented by Dan Vega 5/14Spring into AI presented by Dan Vega 5/14
Spring into AI presented by Dan Vega 5/14
 
Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024
 
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
 
Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...
Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...
Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...
 
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-CloudAlluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
 
Jax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined DeckJax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined Deck
 
[GeeCON2024] How I learned to stop worrying and love the dark silicon apocalypse
[GeeCON2024] How I learned to stop worrying and love the dark silicon apocalypse[GeeCON2024] How I learned to stop worrying and love the dark silicon apocalypse
[GeeCON2024] How I learned to stop worrying and love the dark silicon apocalypse
 
Navigation in flutter – how to add stack, tab, and drawer navigators to your ...
Navigation in flutter – how to add stack, tab, and drawer navigators to your ...Navigation in flutter – how to add stack, tab, and drawer navigators to your ...
Navigation in flutter – how to add stack, tab, and drawer navigators to your ...
 
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
 
Abortion Pill Prices Mthatha (@](+27832195400*)[ 🏥 Women's Abortion Clinic In...
Abortion Pill Prices Mthatha (@](+27832195400*)[ 🏥 Women's Abortion Clinic In...Abortion Pill Prices Mthatha (@](+27832195400*)[ 🏥 Women's Abortion Clinic In...
Abortion Pill Prices Mthatha (@](+27832195400*)[ 🏥 Women's Abortion Clinic In...
 
Microsoft365_Dev_Security_2024_05_16.pdf
Microsoft365_Dev_Security_2024_05_16.pdfMicrosoft365_Dev_Security_2024_05_16.pdf
Microsoft365_Dev_Security_2024_05_16.pdf
 
OpenChain Webinar: AboutCode and Beyond - End-to-End SCA
OpenChain Webinar: AboutCode and Beyond - End-to-End SCAOpenChain Webinar: AboutCode and Beyond - End-to-End SCA
OpenChain Webinar: AboutCode and Beyond - End-to-End SCA
 
BusinessGPT - Security and Governance for Generative AI
BusinessGPT  - Security and Governance for Generative AIBusinessGPT  - Security and Governance for Generative AI
BusinessGPT - Security and Governance for Generative AI
 
GraphSummit Milan - Visione e roadmap del prodotto Neo4j
GraphSummit Milan - Visione e roadmap del prodotto Neo4jGraphSummit Milan - Visione e roadmap del prodotto Neo4j
GraphSummit Milan - Visione e roadmap del prodotto Neo4j
 
A Deep Dive into Secure Product Development Frameworks.pdf
A Deep Dive into Secure Product Development Frameworks.pdfA Deep Dive into Secure Product Development Frameworks.pdf
A Deep Dive into Secure Product Development Frameworks.pdf
 
GraphSummit Milan - Neo4j: The Art of the Possible with Graph
GraphSummit Milan - Neo4j: The Art of the Possible with GraphGraphSummit Milan - Neo4j: The Art of the Possible with Graph
GraphSummit Milan - Neo4j: The Art of the Possible with Graph
 
Transformer Neural Network Use Cases with Links
Transformer Neural Network Use Cases with LinksTransformer Neural Network Use Cases with Links
Transformer Neural Network Use Cases with Links
 

Getting Started with Relay Modern

  • 1.
  • 2.
  • 3. Nikolas Burk 👋 Developer at Graphcool $ whoami @nikolasburk
  • 4. Launch Week 🚀 Product Hunt > 1000 upvotesHacker News #1
  • 6. 1. Relay - A Brief History 2. Data Fetching 3. Mutations 4. More Features in Relay Modern Agenda @nikolasburk
  • 7. Relay - A Brief History @nikolasburk
  • 8. 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
  • 9. GraphQL Clients - homegrown by Facebook - main goal: performance - learning curve - community-driven - main goal: flexibility - easy-to-get-started @nikolasburk
  • 11. 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
  • 12. Declarative Data Fetching with GraphQL 1. describe data dependencies 2. display data in UI 😍 @nikolasburk
  • 13. Relay’s core idea is to couple a view component with its data dependencies @nikolasburk
  • 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. 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. 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. 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. 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
  • 21. 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
  • 22. 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
  • 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. 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. 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. 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
  • 27. 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
  • 28. The QueryRenderer QueryRenderer is the root of a Relay tree. It takes a query, fetches the data and calls the render callback. @nikolasburk
  • 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 } } ` App.js @nikolasburk
  • 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 } } ` App.js @nikolasburk
  • 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 # from ListPage.js } } ` App.js @nikolasburk
  • 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. 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. 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
  • 35. 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
  • 37. 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
  • 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, }, ) @nikolasburk
  • 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. 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
  • 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. 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
  • 43. 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
  • 44. 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
  • 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. 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
  • 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) } const mutation = graphql` mutation CreatePostMutation($input: CreatePostInput!) { createPost(input: $input) { post { id description imageUrl } } } ` @nikolasburk
  • 48. 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
  • 49. 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
  • 50. 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
  • 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. 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
  • 53. 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
  • 54. More Features in Relay Modern @nikolasburk
  • 55. 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
  • 56. GraphQL Subscriptions ⚡ @nikolasburk ….allow to receive realtime events from the server.
  • 57. Client Schema Extensions 💼 @nikolasburk ….allow to store client state. extend type Post { hasViewerSeen: Boolean }
  • 58. Garbage Collection 🗑 @nikolasburk … removes objects from memory before the JS Garbage Collector runs.
  • 59. Compatibility Mode 🎯 @nikolasburk … allows to incrementally update an application from Relay Classic to Relay Modern.
  • 60. 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
  • 61. Community 🙌 • slack.graph.cool (> 2000 members) • GraphQL Weekly Newsletter • GraphQL Radio Podcast @nikolasburk
  • 63. Thank you! 🙇 … any questions? @nikolasburk