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

Abortion Pills For Sale WhatsApp[[+27737758557]] In Birch Acres, Abortion Pil...
Abortion Pills For Sale WhatsApp[[+27737758557]] In Birch Acres, Abortion Pil...Abortion Pills For Sale WhatsApp[[+27737758557]] In Birch Acres, Abortion Pil...
Abortion Pills For Sale WhatsApp[[+27737758557]] In Birch Acres, Abortion Pil...drm1699
 
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
 
Novo Nordisk: When Knowledge Graphs meet LLMs
Novo Nordisk: When Knowledge Graphs meet LLMsNovo Nordisk: When Knowledge Graphs meet LLMs
Novo Nordisk: When Knowledge Graphs meet LLMsNeo4j
 
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale Ibrida
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale IbridaUNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale Ibrida
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale IbridaNeo4j
 
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdf
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdfAzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdf
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdfryanfarris8
 
Modern binary build systems - PyCon 2024
Modern binary build systems - PyCon 2024Modern binary build systems - PyCon 2024
Modern binary build systems - PyCon 2024Henry Schreiner
 
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.
 
Encryption Recap: A Refresher on Key Concepts
Encryption Recap: A Refresher on Key ConceptsEncryption Recap: A Refresher on Key Concepts
Encryption Recap: A Refresher on Key Conceptsthomashtkim
 
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
 
Lessons Learned from Building a Serverless Notifications System.pdf
Lessons Learned from Building a Serverless Notifications System.pdfLessons Learned from Building a Serverless Notifications System.pdf
Lessons Learned from Building a Serverless Notifications System.pdfSrushith Repakula
 
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...Abortion Clinic
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationJuha-Pekka Tolvanen
 
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024SimonedeGijt
 
Workshop - Architecting Innovative Graph Applications- GraphSummit Milan
Workshop -  Architecting Innovative Graph Applications- GraphSummit MilanWorkshop -  Architecting Innovative Graph Applications- GraphSummit Milan
Workshop - Architecting Innovative Graph Applications- GraphSummit MilanNeo4j
 
Effective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeConEffective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeConNatan Silnitsky
 

Recently uploaded (20)

Abortion Pills For Sale WhatsApp[[+27737758557]] In Birch Acres, Abortion Pil...
Abortion Pills For Sale WhatsApp[[+27737758557]] In Birch Acres, Abortion Pil...Abortion Pills For Sale WhatsApp[[+27737758557]] In Birch Acres, Abortion Pil...
Abortion Pills For Sale WhatsApp[[+27737758557]] In Birch Acres, Abortion Pil...
 
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 ...
 
Novo Nordisk: When Knowledge Graphs meet LLMs
Novo Nordisk: When Knowledge Graphs meet LLMsNovo Nordisk: When Knowledge Graphs meet LLMs
Novo Nordisk: When Knowledge Graphs meet LLMs
 
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale Ibrida
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale IbridaUNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale Ibrida
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale Ibrida
 
Abortion Pill Prices Polokwane ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
Abortion Pill Prices Polokwane ](+27832195400*)[ 🏥 Women's Abortion Clinic in...Abortion Pill Prices Polokwane ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
Abortion Pill Prices Polokwane ](+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...
Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
 
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdf
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdfAzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdf
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdf
 
Modern binary build systems - PyCon 2024
Modern binary build systems - PyCon 2024Modern binary build systems - PyCon 2024
Modern binary build systems - PyCon 2024
 
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
 
Encryption Recap: A Refresher on Key Concepts
Encryption Recap: A Refresher on Key ConceptsEncryption Recap: A Refresher on Key Concepts
Encryption Recap: A Refresher on Key Concepts
 
Abortion Clinic in Bloemfontein [(+27832195400*)]🏥Safe Abortion Pills In Bloe...
Abortion Clinic in Bloemfontein [(+27832195400*)]🏥Safe Abortion Pills In Bloe...Abortion Clinic in Bloemfontein [(+27832195400*)]🏥Safe Abortion Pills In Bloe...
Abortion Clinic in Bloemfontein [(+27832195400*)]🏥Safe Abortion Pills In Bloe...
 
Abortion Pill Prices Rustenburg [(+27832195400*)] 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Rustenburg [(+27832195400*)] 🏥 Women's Abortion Clinic i...Abortion Pill Prices Rustenburg [(+27832195400*)] 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Rustenburg [(+27832195400*)] 🏥 Women's Abortion Clinic i...
 
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
 
Lessons Learned from Building a Serverless Notifications System.pdf
Lessons Learned from Building a Serverless Notifications System.pdfLessons Learned from Building a Serverless Notifications System.pdf
Lessons Learned from Building a Serverless Notifications System.pdf
 
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
 
Workshop - Architecting Innovative Graph Applications- GraphSummit Milan
Workshop -  Architecting Innovative Graph Applications- GraphSummit MilanWorkshop -  Architecting Innovative Graph Applications- GraphSummit Milan
Workshop - Architecting Innovative Graph Applications- GraphSummit Milan
 
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...
 
Effective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeConEffective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeCon
 

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