Taming Data FetchingFrom pure React hooks to Relay Modern and SuspenseSibelius Seraphini
Sibelius Seraphini
@sibelius
@sseraphini
Abstraction Engineer

Overview

  • Motivation
  • History/Evolution

Motivation

  • What is Data Fetching?
  • Why do we need Data Fetching?
  • Why is it hard?

What is Data Fetching?

  • It is the reading/retrieve of data from somewhere
  • You can fetch data from local storage (disk) or network storage (server)

Network Data Fetching Example

Why do we need Data Fetching?

  • We can't keep all app data in memory
  • We can't download all app user data locally
  • We just want to fetch the data we are using

Why is it hard?

  • We don't want to overfetch (retrieve more data that we need)
  • We don't want to underfetch (retrieve less data that we need)

Why is it hard?

  • We need to know from where we can get the data we need
  • We can have more than one "endpoint" to get the data
  • We want to cache data already fetched, so we don't waste network resources

Why is it hard?

  • Optimistic Updates
  • Offline support
  • Local First Architecture
  • Realtime
  • Server Side Rendering

Imperative Data Fetching

  • We define step by step how to do the data fetching logic
  • We define the endpoints
  • We define how to cache/store the data
  • We define how to invalidate stale data
  • We define when to do data fetching

Imperative Data Fetching

Declarative Data Fetching

  • You define the data which components needs
  • GraphQL made this pattern possible
  • Relay/Apollo makes sure the data is ready when rendering the components

Declarative Data Fetching

History/Evolution

  • componentDidMount

ComponentDidMount

ComponentDidMount drawbacks

  • class api
  • data fetching logic spread on component lifecycles
  • imperative api
  • render then fetch (request waterfall)
  • setState on unmounted components

Request Waterfall

  • You first fetch code (code split)
  • then you fetch data

Request Waterfall

History/Evolution

  • componentDidMount
  • Redux Thunk

Redux Thunk

Redux Thunk drawbacks

  • imperative api
  • hard to sync loading state with component

History/Evolution

  • componentDidMount
  • Redux Thunk
  • Redux Saga

Redux Saga

Redux Saga drawbacks

  • same as Redux Thunk

History/Evolution

  • componentDidMount
  • Redux Thunk
  • Redux Saga
  • useEffect hook

UseEffect

UseEffect drawbacks

  • imperative api
  • keep state of loading, error, isMounted, fetch cancelling
  • hard to handle race conditions

Data Fetching Race Conditions

Why Data Fetching Race Conditions happens?

  • network can be slow
  • backend could be under heavy load
  • user is typing too fast
  • you are unlucky
  • debounce is not enough

How to "solve" Data Fetching Race Conditions

  • ignore responses from former api calls
  • cancel former api calls

Custom Hooks for Imperative Data Fetching

  • use-async-effect
  • react-hooks-fetch

Custom Hooks for Imperative Data Fetching

  • remove some pain points of imperative data fetching
  • keep state of loading, error, isMounted and fetch cancelling

History/Evolution

  • componentDidMount
  • Redux Thunk
  • Redux Saga
  • useEffect hook
  • Relay HOCs

Relay HOCs

Relay HOCs

  • declarative data fetching
  • data components

Relay fragments understanding

Relay HOCs Drawbacks

  • HOC API - more "components" in the tree
  • render props API to handle loading and error state
  • HOCs needs to be explicit typed

History/Evolution

  • componentDidMount
  • Redux Thunk
  • Redux Saga
  • useEffect hook
  • Relay HOCs
  • Suspense

Suspense

  • Allows you to suspend component rendering until a condition is met
  • While waiting, a fallback component is rendered

Suspense

Suspend on Code Loading

Suspense for Data Fetching

Suspense Resource

Suspense Resource State Machine

Suspense Resource Pseudo Algorithm

  • Try to read entry from cache
  • If request is pending, throw promise (react will suspend the component)
  • If request is reject, throw error (error boundary will catch the error)
  • When request promise is resolved react will render again your component
  • Go back to first step

Benefits of Suspense

  • it only shows Loading indicator when loading/fetch is slow enough
  • it "transforms" Async in Synchronous

History/Evolution

  • componentDidMount
  • Redux Thunk
  • Redux Saga
  • useEffect hook
  • Relay HOCs
  • Suspense
  • Relay hooks + Suspense

Relay Modern Hooks with Suspense

  • 2 Resources
  • QueryResource to cache Queries
  • FramentResource to cache Fragments
  • UNSTABLE (use at your own risk)

useLazyLoadQuery

ErrorBoundaryWithRetry + Suspense Fallback Wrapper

useFragment

useRefetchableFragment

Query Resource Fetch Policy

  • store-only
  • store-or-network
  • store-and-network
  • network-only

Query Resource Render Policy

  • full
  • partial

Data Driven Code-splitting

Data Driven Code-splitting

  • Data decides which components to load and render
  • Preload required components

Benefits of new API

  • better fetch and render policies (faster render)
  • components suspended based on fragments (instead of waiting full Query to finish)
  • less components in the tree (no more HOCs)

Benefits of new API

  • less boilerplate (refetchable queries are autogenerated by relay compiler)
  • only components that reference a fragment are updated (vs whole tree on apollo/redux)
  • data driven code-splitting

Should we suspend on Refetch?

  • It depends
  • Blocking vs Non-Blocking pagination

How to control suspend behavior?

What's Next?

  • Stable React Suspense Concurrent Mode
  • Stable Relay Modern Hooks
  • Stable Scheduler APIs
  • @defer/@stream GraphQL/Relay

References

  • Distributed State
  • Linear Publish Queue
  • Fresh Concurrent React
  • Suspense and Concurrent Mode
  • Concurrent Rendering in React - ReactConf 2018
  • Moving To React Suspense

References

  • Beyond React 16
  • REST hooks
  • Poor man's algebraic effects
  • A Complete Guide to useEffect
  • Handling API request race conditions in React
  • Building the New Facebook
  • Algebraic Effects
  • React Suspense Netlify

References

  • Local-first Software
  • React Relay Offline
  • Wora - Cache and Offline handling
  • useFragment explanation
  • Automerge

References

  • use-async-effect
  • react-hooks-fetch
  • @match and @module
Thanks!
We are hiring!
https://entria.contrata.vc
Give me a Feedback:
https://entria.feedback.house/sibelius