SlideShare a Scribd company logo
Boris Litvinsky, Tech Lead @ Wix
Road to Async Nirvana
borisl@wix.com twitter@borislit linkedin/borislit github.com/borislit
class ProfilePage extends Component {
constructor () {
this.state = {
error: false,
};
}
componentDidMount () {
fetchUser()
.then(user => {
this.setState({
user,
});
})
.catch(() => this.setState({ error: true }));
}
//...
//...
render() {
if (this.state.error) {
return <p>Error!</p>;
}
if (!this.state.user) {
return <p>Loading profile...</ p>;
}
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline />
</>
);
}
}
class ProfilePage extends Component {
constructor() {
this.state = {
error: false,
};
}
componentDidMount() {
fetchUser()
.then(user => {
this.setState({
user,
});
})
.catch(() => this.setState({ error: true }));
}
//...
//...
render() {
if (this.state.error) {
return <p>Error!</p>;
}
if (!this.state.user) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline />
</>
);
}
}
class ProfilePage extends Component {
constructor() {
this.state = {
error: false,
};
}
componentDidMount() {
fetchUser()
.then( user => {
this.setState({
user,
});
})
.catch(() => this.setState({ error: true }));
}
//...
//...
render() {
if (this.state.error) {
return <p>Error!</p>;
}
if (!this.state.user) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline />
</>
);
}
}
How is this OK???
This is NOT HOW YOU WRITE JAVASCRIPT!
THIS is how You write Javascript!
function ProfilePage() {
console.log('Loading User Profile...' );
try {
const timeline = await ProfileTimeline ();
console.log('Timeline', timeline);
} catch (e) {
console.log('Error', e);
}
}
Hooks for fetching, caching and updating
asynchronous data in React
But First,
Let’s talk Hook
Component
Props
State
UI
React in a Slide
Component
Props
State
UI
React in a Slide
Missing in Functional
Component
function ProfilePage() {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser().then(u => setUser(u));
}, []);
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline />
</>
);
}
▪ useState is a Hook
that lets you add
React state to
function components
function ProfilePage() {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser().then(u => setUser(u));
}, []);
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline />
</>
);
}
▪ useState is a Hook
that lets you add
React state to
function components
▪ useEffect lets you
perform side effects in
function components
function ProfilePage() {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser().then(u => setUser(u));
}, []);
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline />
</>
);
}
▪ useState is a Hook
that lets you add
React state to
function components
▪ useEffect lets you
perform side effects in
function components
function ProfilePage() {
const [user, setUser] = useState(null);
const [error, setError] = useState(false);
useEffect(() => {
fetchUser().then(u => setUser(u)).catch(() => setUser(true));
}, []);
if (error) {
return <p>Error!</p>;
}
if (user === null) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline />
</>
);
}
▪ Compose hooks to
create custom hooks
function useProfile() {
const [user, setUser] = useState(null);
const [error, setError] = useState(false);
useEffect(() => {
fetchUser().then(u => setUser(u)).catch(() => setUser(true));
}, []);
return {user , error};
}
function ProfilePage() {
const {user, error} = useProfile();
if (user === null) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline />
</>
);
}
Components are Functions
Hooks are Functions
Functions can Compose
▪ Compose hooks to
create custom hooks
function useProfile() {
const [user, setUser] = useState(null);
const [error, setError] = useState(false);
useEffect(() => {
fetchUser().then(u => setUser(u)).catch(() => setUser(true));
}, []);
return {user , error};
}
function ProfilePage() {
const {user, error} = useProfile();
if (user === null) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline />
</>
);
}
Road to Async Nirvana
The Component...
▪ Doesn’t know what’s the source of the data
▪ Does know that it will be notified when the data changes
New Dog, Old Issue
function useProfile() {
const [user, setUser] = useState(null);
const [error, setError] = useState(false);
useEffect(() => {
fetchUser().then(u => setUser(u)).catch(() => setUser(true));
}, []);
return { user, error };
}
function ProfilePage() {
const { user, error } = useProfile();
if (user === null) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline />
</>
);
}
Local to a Component
React
Context
State
Management
Not All State is Born Equal
▪ Server state and component state serve different purposes
▪ Server state is global, while component state is local
▪ Server has unique concerns (caching, pagination, synchronization)
Not All State is Born Equal
Enter
1. Abstracts Away Async
Call
2. Handles requests
states
3. Stores Results in a
cache
function useProfile() {
const [user, setUser] = useState(null);
const [error, setError] = useState(false);
useEffect(() => {
fetchUser().then(u => setUser(u)).catch(() => setUser(true));
}, []);
return { user, error };
}
function ProfilePage() {
const { user, error } = useProfile();
if (user === null) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline />
</>
);
}
function useProfile() {
return useQuery([user, id],(id) => fetchUser(id));
}
function ProfilePage() {
const { user, error } = useProfile();
if (user === null) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline />
</>
);
}
1. Abstracts Away Async
Call
2. Handles requests
states
3. Stores Results in a
cache
React Query Gives You...
▪ Loading states
▪ Mutations
▪ Optimistic updates
▪ Calls de-duping
▪ Pagination
▪ Query Dependencies
▪ Caching
const {
isLoading,
isSuccess,
isError,
data,
error,
failureCount,
refetch,
retry
} = useQuery(/*..*/)
const [mutate] = useMutation(addTodo, {
onSuccess: () => {
queryCache.refetchQueries('todos')
queryCache.refetchQueries('reminders')
},
})
Query/Mutation Dependency
Caching
function ChildComponent() {
const { data } = useQuery('todo');
return <div>{data}</div>;
}
function Root() {
const { data } = useQuery('todo');
//Do Something With Todos
return <ChildComponent />;
}
Resolved from
cache
Fires a request
Road to Async Nirvana
Self Contained Components
Location-Independent
Caching
function ChildComponent() {
const { data } = useQuery('todo');
return <div>{data}</div>;
}
function Root() {
const { data } = useQuery('todo');
const [shouldRenderChild, setShouldRenderChild] = useState(false);
//Do Something With Todos
return <div>{shouldRenderChild && <ChildComponent />} </div>;
}
Resolved from
cache
Fires a request
This can be Addictive
Caching
function ChildComponent() {
const { data } = useQuery('todo');
return <div>{data}</div>;
}
function Root() {
const { data } = useQuery('todo');
//Do Something With Todos
return <ChildComponent />;
}
ChildComponent tests
become async
Root tests
become async
Leaving You with some Suspense
Where we stand function ProfilePage() {
const { user, isError, isLoading } = useProfile();
if (isError) {
return <p>Error</p>;
}
if (isLoading) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{data.name}</h1>
</>
);
}
Where we stand
▪ Handle missing data
▪ Handling errors
▪ Boilerplate
▪ What if the
component is
reusable?
function ProfilePage() {
const { user, isError, isLoading } = useProfile();
if (isError) {
return <p>Error</p>;
}
if (isLoading) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{data.name}</h1>
</>
);
}
THIS is how You write Javascript!
function ProfilePage() {
console.log('Loading User Profile...' );
try {
const timeline = await ProfileTimeline ();
console.log('Timeline', timeline);
} catch (e) {
console.log('Error', e);
}
}
Where we stand
function ProfilePage() {
const { user, isError, isLoading } = useProfile();
if (isError) {
return <p>Error</p>;
}
if (isLoading) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{data.name}</h1>
</>
);
}
Solved by
Error Boundaries
Where we stand function ProfilePage() {
const { user, isLoading } = useProfile();
if (isLoading) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{data.name}</h1>
</>
);
}
<ErrorBoundery>
<ProfilePage />
</ErrorBoundery>
Error Boundary
Where we stand
function ProfilePage() {
const { user, isLoading } = useProfile();
if (isLoading) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{data.name}</h1>
</>
);
}
?
<Suspense> component lets you “wait” for any
asynchronous work and declaratively specify a
loading state (like a spinner) while we’re waiting
The Suspense Way
▪ Try to render ProfileDetails
▪ ProfileDetails tries reading
user details
▪ React “suspends”
ProfileDetails rendering and
renders fallback
▪ React “resumes”
ProfileDetails rendering once
user details are available
function ProfilePage() {
return (
<Suspense fallback={<h1>Loading profile...</h1>}>
<ProfileDetails />
</Suspense>
);
}
function ProfileDetails() {
// Try to read user info, although it might not have loaded yet
const user = useProfile();
return <h1>{user.name}</h1>;
}
The Suspense Way
▪ Suspense is a
component
▪ “Suspended”
components will fallback
to the closest Suspense
ancestor
function ProfilePage() {
return (
<Suspense fallback={<h1>Loading profile...</h1>}>
<ProfileDetails />
<Suspense fallback={<h1>Loading posts...</h1>}>
<ProfileTimeline />
</Suspense>
</Suspense>
);
}
function ProfileDetails() {
const user = useProfile();
return <h1>{user.name}</h1>;
}
This is HARD*
function Root() {
const { data } = useQuery('todo');
return <ChildComponent />;
}
React-Query supports Suspense OOB
Suspends
Rendering
This get EVERYBODY...
▪ Thinking about resilience
▪ Thinking about performance
At Wix this is now an integral part of product
design and architecture review
Summary
Summary
▪ Hooks are a paradigm shift
▪ React Query uses hooks to simplify fetching/mutating async data
▪ React Query classifying your state.
▪ Cache responses allows co locating the data requirements with the
components
▪ Combined with Suspense, it promotes error handling, resilience and
performances
Thank You
borisl@wix.com twitter@borislit linkedin/borislit github.com/borislit

More Related Content

PDF
jQuery: Events, Animation, Ajax
DOCX
Borrador del blog
PDF
Mashing up JavaScript
PPTX
Nodejs do teste de unidade ao de integração
PDF
DOM Scripting Toolkit - jQuery
PDF
Django Class-based views (Slovenian)
PDF
Mashing up JavaScript – Advanced Techniques for modern Web Apps
PDF
Delivering a Responsive UI
jQuery: Events, Animation, Ajax
Borrador del blog
Mashing up JavaScript
Nodejs do teste de unidade ao de integração
DOM Scripting Toolkit - jQuery
Django Class-based views (Slovenian)
Mashing up JavaScript – Advanced Techniques for modern Web Apps
Delivering a Responsive UI

What's hot (20)

PDF
The Rails Way
PDF
Beyond the DOM: Sane Structure for JS Apps
PDF
Functionality Focused Code Organization
PDF
Laravel 로 배우는 서버사이드 #5
PDF
Building evented single page applications
PDF
jQuery: out with the old, in with the new
KEY
Advanced jQuery
PDF
YUI on the go
KEY
Jquery Fundamentals
KEY
JQuery In Rails
PDF
Symfony2. Form and Validation
PDF
Acceptance Testing with Webrat
PDF
Growing jQuery
KEY
PDF
jQuery and Rails, Sitting in a Tree
PDF
Tinkerbelles return home from their Guinness world-record attempt on Sunday
PPTX
Dundee University HackU 2013 - Mojito
PDF
Backbone - TDC 2011 Floripa
ODP
FRP and Bacon.js
The Rails Way
Beyond the DOM: Sane Structure for JS Apps
Functionality Focused Code Organization
Laravel 로 배우는 서버사이드 #5
Building evented single page applications
jQuery: out with the old, in with the new
Advanced jQuery
YUI on the go
Jquery Fundamentals
JQuery In Rails
Symfony2. Form and Validation
Acceptance Testing with Webrat
Growing jQuery
jQuery and Rails, Sitting in a Tree
Tinkerbelles return home from their Guinness world-record attempt on Sunday
Dundee University HackU 2013 - Mojito
Backbone - TDC 2011 Floripa
FRP and Bacon.js
Ad

Similar to Road to Async Nirvana (20)

PPTX
jQuery Data Manipulate API - A source code dissecting journey
PDF
Building Evented Single Page Applications
PDF
Reduxing like a pro
PDF
HTML5 APIs - Where no man has gone before! - Altran
PPTX
Orchestrating things in Angular application
PPTX
Angular Workshop_Sarajevo2
PDF
Creating an Uber Clone - Part XXXX.pdf
PPT
Django
PDF
async/await in Swift
PDF
JavaScript Promise
PDF
The Beauty Of Java Script V5a
PDF
Clean Javascript
PDF
PDF
JavaScript patterns
PDF
Functional programming using underscorejs
PPTX
Express JS
PDF
The Beauty of Java Script
PDF
JSGeneve - Backbone.js
DOCX
Week 12 code
PDF
Stop Making Excuses and Start Testing Your JavaScript
jQuery Data Manipulate API - A source code dissecting journey
Building Evented Single Page Applications
Reduxing like a pro
HTML5 APIs - Where no man has gone before! - Altran
Orchestrating things in Angular application
Angular Workshop_Sarajevo2
Creating an Uber Clone - Part XXXX.pdf
Django
async/await in Swift
JavaScript Promise
The Beauty Of Java Script V5a
Clean Javascript
JavaScript patterns
Functional programming using underscorejs
Express JS
The Beauty of Java Script
JSGeneve - Backbone.js
Week 12 code
Stop Making Excuses and Start Testing Your JavaScript
Ad

More from Boris Litvinsky (7)

PDF
ReactiveConf - Not all indecision are bad
PDF
Your IDE Deserves Better
PDF
The ultimate guide for Software Procrastination
PDF
CDD @ FED
PDF
Test Driven Culture
PDF
How to build 100m websites
PDF
Name in Vain: Improving design one word at a time
ReactiveConf - Not all indecision are bad
Your IDE Deserves Better
The ultimate guide for Software Procrastination
CDD @ FED
Test Driven Culture
How to build 100m websites
Name in Vain: Improving design one word at a time

Recently uploaded (20)

PDF
Automation-in-Manufacturing-Chapter-Introduction.pdf
PPTX
introduction to high performance computing
PPTX
Artificial Intelligence
PDF
The CXO Playbook 2025 – Future-Ready Strategies for C-Suite Leaders Cerebrai...
PPTX
UNIT - 3 Total quality Management .pptx
PDF
BIO-INSPIRED HORMONAL MODULATION AND ADAPTIVE ORCHESTRATION IN S-AI-GPT
PPTX
Safety Seminar civil to be ensured for safe working.
PPTX
6ME3A-Unit-II-Sensors and Actuators_Handouts.pptx
PPT
A5_DistSysCh1.ppt_INTRODUCTION TO DISTRIBUTED SYSTEMS
PDF
Soil Improvement Techniques Note - Rabbi
PDF
Integrating Fractal Dimension and Time Series Analysis for Optimized Hyperspe...
PPT
Occupational Health and Safety Management System
PDF
Abrasive, erosive and cavitation wear.pdf
PPTX
Current and future trends in Computer Vision.pptx
PDF
737-MAX_SRG.pdf student reference guides
PPT
introduction to datamining and warehousing
PDF
A SYSTEMATIC REVIEW OF APPLICATIONS IN FRAUD DETECTION
PDF
Artificial Superintelligence (ASI) Alliance Vision Paper.pdf
PDF
R24 SURVEYING LAB MANUAL for civil enggi
PPT
INTRODUCTION -Data Warehousing and Mining-M.Tech- VTU.ppt
Automation-in-Manufacturing-Chapter-Introduction.pdf
introduction to high performance computing
Artificial Intelligence
The CXO Playbook 2025 – Future-Ready Strategies for C-Suite Leaders Cerebrai...
UNIT - 3 Total quality Management .pptx
BIO-INSPIRED HORMONAL MODULATION AND ADAPTIVE ORCHESTRATION IN S-AI-GPT
Safety Seminar civil to be ensured for safe working.
6ME3A-Unit-II-Sensors and Actuators_Handouts.pptx
A5_DistSysCh1.ppt_INTRODUCTION TO DISTRIBUTED SYSTEMS
Soil Improvement Techniques Note - Rabbi
Integrating Fractal Dimension and Time Series Analysis for Optimized Hyperspe...
Occupational Health and Safety Management System
Abrasive, erosive and cavitation wear.pdf
Current and future trends in Computer Vision.pptx
737-MAX_SRG.pdf student reference guides
introduction to datamining and warehousing
A SYSTEMATIC REVIEW OF APPLICATIONS IN FRAUD DETECTION
Artificial Superintelligence (ASI) Alliance Vision Paper.pdf
R24 SURVEYING LAB MANUAL for civil enggi
INTRODUCTION -Data Warehousing and Mining-M.Tech- VTU.ppt

Road to Async Nirvana

  • 1. Boris Litvinsky, Tech Lead @ Wix Road to Async Nirvana borisl@wix.com twitter@borislit linkedin/borislit github.com/borislit
  • 2. class ProfilePage extends Component { constructor () { this.state = { error: false, }; } componentDidMount () { fetchUser() .then(user => { this.setState({ user, }); }) .catch(() => this.setState({ error: true })); } //... //... render() { if (this.state.error) { return <p>Error!</p>; } if (!this.state.user) { return <p>Loading profile...</ p>; } return ( <> <h1>{user.name}</h1> <ProfileTimeline /> </> ); } }
  • 3. class ProfilePage extends Component { constructor() { this.state = { error: false, }; } componentDidMount() { fetchUser() .then(user => { this.setState({ user, }); }) .catch(() => this.setState({ error: true })); } //... //... render() { if (this.state.error) { return <p>Error!</p>; } if (!this.state.user) { return <p>Loading profile...</p>; } return ( <> <h1>{user.name}</h1> <ProfileTimeline /> </> ); } }
  • 4. class ProfilePage extends Component { constructor() { this.state = { error: false, }; } componentDidMount() { fetchUser() .then( user => { this.setState({ user, }); }) .catch(() => this.setState({ error: true })); } //... //... render() { if (this.state.error) { return <p>Error!</p>; } if (!this.state.user) { return <p>Loading profile...</p>; } return ( <> <h1>{user.name}</h1> <ProfileTimeline /> </> ); } }
  • 5. How is this OK??? This is NOT HOW YOU WRITE JAVASCRIPT!
  • 6. THIS is how You write Javascript! function ProfilePage() { console.log('Loading User Profile...' ); try { const timeline = await ProfileTimeline (); console.log('Timeline', timeline); } catch (e) { console.log('Error', e); } }
  • 7. Hooks for fetching, caching and updating asynchronous data in React
  • 10. Component Props State UI React in a Slide Missing in Functional Component
  • 11. function ProfilePage() { const [user, setUser] = useState(null); useEffect(() => { fetchUser().then(u => setUser(u)); }, []); return ( <> <h1>{user.name}</h1> <ProfileTimeline /> </> ); }
  • 12. ▪ useState is a Hook that lets you add React state to function components function ProfilePage() { const [user, setUser] = useState(null); useEffect(() => { fetchUser().then(u => setUser(u)); }, []); return ( <> <h1>{user.name}</h1> <ProfileTimeline /> </> ); }
  • 13. ▪ useState is a Hook that lets you add React state to function components ▪ useEffect lets you perform side effects in function components function ProfilePage() { const [user, setUser] = useState(null); useEffect(() => { fetchUser().then(u => setUser(u)); }, []); return ( <> <h1>{user.name}</h1> <ProfileTimeline /> </> ); }
  • 14. ▪ useState is a Hook that lets you add React state to function components ▪ useEffect lets you perform side effects in function components function ProfilePage() { const [user, setUser] = useState(null); const [error, setError] = useState(false); useEffect(() => { fetchUser().then(u => setUser(u)).catch(() => setUser(true)); }, []); if (error) { return <p>Error!</p>; } if (user === null) { return <p>Loading profile...</p>; } return ( <> <h1>{user.name}</h1> <ProfileTimeline /> </> ); }
  • 15. ▪ Compose hooks to create custom hooks function useProfile() { const [user, setUser] = useState(null); const [error, setError] = useState(false); useEffect(() => { fetchUser().then(u => setUser(u)).catch(() => setUser(true)); }, []); return {user , error}; } function ProfilePage() { const {user, error} = useProfile(); if (user === null) { return <p>Loading profile...</p>; } return ( <> <h1>{user.name}</h1> <ProfileTimeline /> </> ); }
  • 16. Components are Functions Hooks are Functions Functions can Compose
  • 17. ▪ Compose hooks to create custom hooks function useProfile() { const [user, setUser] = useState(null); const [error, setError] = useState(false); useEffect(() => { fetchUser().then(u => setUser(u)).catch(() => setUser(true)); }, []); return {user , error}; } function ProfilePage() { const {user, error} = useProfile(); if (user === null) { return <p>Loading profile...</p>; } return ( <> <h1>{user.name}</h1> <ProfileTimeline /> </> ); }
  • 19. The Component... ▪ Doesn’t know what’s the source of the data ▪ Does know that it will be notified when the data changes
  • 20. New Dog, Old Issue
  • 21. function useProfile() { const [user, setUser] = useState(null); const [error, setError] = useState(false); useEffect(() => { fetchUser().then(u => setUser(u)).catch(() => setUser(true)); }, []); return { user, error }; } function ProfilePage() { const { user, error } = useProfile(); if (user === null) { return <p>Loading profile...</p>; } return ( <> <h1>{user.name}</h1> <ProfileTimeline /> </> ); } Local to a Component
  • 23. Not All State is Born Equal ▪ Server state and component state serve different purposes ▪ Server state is global, while component state is local ▪ Server has unique concerns (caching, pagination, synchronization)
  • 24. Not All State is Born Equal
  • 25. Enter
  • 26. 1. Abstracts Away Async Call 2. Handles requests states 3. Stores Results in a cache function useProfile() { const [user, setUser] = useState(null); const [error, setError] = useState(false); useEffect(() => { fetchUser().then(u => setUser(u)).catch(() => setUser(true)); }, []); return { user, error }; } function ProfilePage() { const { user, error } = useProfile(); if (user === null) { return <p>Loading profile...</p>; } return ( <> <h1>{user.name}</h1> <ProfileTimeline /> </> ); }
  • 27. function useProfile() { return useQuery([user, id],(id) => fetchUser(id)); } function ProfilePage() { const { user, error } = useProfile(); if (user === null) { return <p>Loading profile...</p>; } return ( <> <h1>{user.name}</h1> <ProfileTimeline /> </> ); } 1. Abstracts Away Async Call 2. Handles requests states 3. Stores Results in a cache
  • 28. React Query Gives You... ▪ Loading states ▪ Mutations ▪ Optimistic updates ▪ Calls de-duping ▪ Pagination ▪ Query Dependencies ▪ Caching const { isLoading, isSuccess, isError, data, error, failureCount, refetch, retry } = useQuery(/*..*/)
  • 29. const [mutate] = useMutation(addTodo, { onSuccess: () => { queryCache.refetchQueries('todos') queryCache.refetchQueries('reminders') }, }) Query/Mutation Dependency
  • 30. Caching function ChildComponent() { const { data } = useQuery('todo'); return <div>{data}</div>; } function Root() { const { data } = useQuery('todo'); //Do Something With Todos return <ChildComponent />; } Resolved from cache Fires a request
  • 33. Caching function ChildComponent() { const { data } = useQuery('todo'); return <div>{data}</div>; } function Root() { const { data } = useQuery('todo'); const [shouldRenderChild, setShouldRenderChild] = useState(false); //Do Something With Todos return <div>{shouldRenderChild && <ChildComponent />} </div>; } Resolved from cache Fires a request
  • 34. This can be Addictive
  • 35. Caching function ChildComponent() { const { data } = useQuery('todo'); return <div>{data}</div>; } function Root() { const { data } = useQuery('todo'); //Do Something With Todos return <ChildComponent />; } ChildComponent tests become async Root tests become async
  • 36. Leaving You with some Suspense
  • 37. Where we stand function ProfilePage() { const { user, isError, isLoading } = useProfile(); if (isError) { return <p>Error</p>; } if (isLoading) { return <p>Loading profile...</p>; } return ( <> <h1>{data.name}</h1> </> ); }
  • 38. Where we stand ▪ Handle missing data ▪ Handling errors ▪ Boilerplate ▪ What if the component is reusable? function ProfilePage() { const { user, isError, isLoading } = useProfile(); if (isError) { return <p>Error</p>; } if (isLoading) { return <p>Loading profile...</p>; } return ( <> <h1>{data.name}</h1> </> ); }
  • 39. THIS is how You write Javascript! function ProfilePage() { console.log('Loading User Profile...' ); try { const timeline = await ProfileTimeline (); console.log('Timeline', timeline); } catch (e) { console.log('Error', e); } }
  • 40. Where we stand function ProfilePage() { const { user, isError, isLoading } = useProfile(); if (isError) { return <p>Error</p>; } if (isLoading) { return <p>Loading profile...</p>; } return ( <> <h1>{data.name}</h1> </> ); } Solved by Error Boundaries
  • 41. Where we stand function ProfilePage() { const { user, isLoading } = useProfile(); if (isLoading) { return <p>Loading profile...</p>; } return ( <> <h1>{data.name}</h1> </> ); } <ErrorBoundery> <ProfilePage /> </ErrorBoundery> Error Boundary
  • 42. Where we stand function ProfilePage() { const { user, isLoading } = useProfile(); if (isLoading) { return <p>Loading profile...</p>; } return ( <> <h1>{data.name}</h1> </> ); } ?
  • 43. <Suspense> component lets you “wait” for any asynchronous work and declaratively specify a loading state (like a spinner) while we’re waiting
  • 44. The Suspense Way ▪ Try to render ProfileDetails ▪ ProfileDetails tries reading user details ▪ React “suspends” ProfileDetails rendering and renders fallback ▪ React “resumes” ProfileDetails rendering once user details are available function ProfilePage() { return ( <Suspense fallback={<h1>Loading profile...</h1>}> <ProfileDetails /> </Suspense> ); } function ProfileDetails() { // Try to read user info, although it might not have loaded yet const user = useProfile(); return <h1>{user.name}</h1>; }
  • 45. The Suspense Way ▪ Suspense is a component ▪ “Suspended” components will fallback to the closest Suspense ancestor function ProfilePage() { return ( <Suspense fallback={<h1>Loading profile...</h1>}> <ProfileDetails /> <Suspense fallback={<h1>Loading posts...</h1>}> <ProfileTimeline /> </Suspense> </Suspense> ); }
  • 46. function ProfileDetails() { const user = useProfile(); return <h1>{user.name}</h1>; } This is HARD*
  • 47. function Root() { const { data } = useQuery('todo'); return <ChildComponent />; } React-Query supports Suspense OOB Suspends Rendering
  • 48. This get EVERYBODY... ▪ Thinking about resilience ▪ Thinking about performance
  • 49. At Wix this is now an integral part of product design and architecture review
  • 51. Summary ▪ Hooks are a paradigm shift ▪ React Query uses hooks to simplify fetching/mutating async data ▪ React Query classifying your state. ▪ Cache responses allows co locating the data requirements with the components ▪ Combined with Suspense, it promotes error handling, resilience and performances
  • 52. Thank You borisl@wix.com twitter@borislit linkedin/borislit github.com/borislit