/** * Since solution using Suspense API we should be looking at Render-as-you-fetch pattern. * Start fetching all the required data for the next screen as early as possible, and start rendering the new screen immediately. * * The 3-state pattern is very common for loading any resources. * It is in fact so common that it has a name. * Any object containing a read function that behaves like this 3-state pattern, is called a resource. * * Issues * 1) Suspense tag missing attribute 'fallback' prop * 2) Data is not being fetched early * 3) Fetching data on useEffect might cause Race condition. using UseEffect is like Fetch-Then-Render pattern we should avoid. * * Optional but Useful: Handling Errors * Since we are using Promises, we might use catch() to handle errors. * Use ErrorBoundary class and then we can put it anywhere in the tree to catch errors */ import React, { Suspense } from "react"; // Error boundaries currently have to be classes. class ErrorBoundary extends React.Component { state = { hasError: false, error: null }; static getDerivedStateFromError(error) { return { hasError: true, error }; } render() { if (this.state.hasError) { return this.props.fallback; } return this.props.children; } } function fetchProfileData(userId) { let userPromise = fetchUserProfilePromise(userId); return wrapPromise(userPromise); } // Suspense integrations like Relay implement // a contract like this to integrate with React. // Real implementations can be significantly more complex. // Don't copy-paste this into your project! function wrapPromise(promise) { let status = "pending"; let result; let suspender = promise.then( (r) => { status = "success"; result = r; }, (e) => { status = "error"; result = e; } ); return { read() { if (status === "pending") { throw suspender; } else if (status === "error") { throw result; } else if (status === "success") { return result; } } }; } const fetchUserProfilePromise = (userId) => fetch(`https://jsonplaceholder.typicode.com/users/${userId}`).then((res) => res.json() ); const SuspensefulUserProfile = ({ resource }) => { const data = resource.read(); return ; }; const UserProfile = ({ data }) => { return ( <>

{data.name}

{data.email}

); }; const UserProfileList = () => ( <> Loading ...}> Could not fetch user profile.}> ); export default UserProfileList;