Taming Data Fetching
From pure React hooks to Relay Modern and Suspense
Sibelius 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