Created
May 12, 2026 23:03
-
-
Save davidystephenson/139b5d2c8d5ca1256b5098c46d785e93 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 'use client' | |
| import { Suspense } from "react" | |
| // import { useState, useEffect, Suspense } from 'react' | |
| interface Result { | |
| message: string | |
| } | |
| // V1 - fetch in useEffect | |
| // Pros: Universal, traditional | |
| // Cons: Ugly, not readable, no SSR | |
| // export default function Test() { | |
| // const [result, setResult] = useState<Result>() | |
| // useEffect(() => { | |
| // async function fetchDog () { | |
| // const response = await fetch(URL) | |
| // const data = await response.json() | |
| // setResult(data) | |
| // } | |
| // fetchDog() | |
| // }, []) | |
| // return ( | |
| // <> | |
| // <h1>Dog App</h1> | |
| // <div>Here is a picture of a dog:</div> | |
| // {result | |
| // ? <img src={result?.message} width={300} /> | |
| // : <div>Loading...</div> | |
| // } | |
| // </> | |
| // ) | |
| // } | |
| // V2 - async component with suspense inside client component | |
| // Pros: Clean, readable, Universal | |
| // Cons: no SSR | |
| // async function Dog() { | |
| // const response = await fetch(URL) | |
| // const data = await response.json() | |
| // return <img src={data.message} width={300} /> | |
| // } | |
| // export default function Test() { | |
| // return ( | |
| // <> | |
| // <h1>Dog App</h1> | |
| // <div>Here is a picture of a dog:</div> | |
| // <Suspense fallback={<div>Loading...</div>}> | |
| // <Dog /> | |
| // </Suspense> | |
| // </> | |
| // ) | |
| // } | |
| // V3 - async page component | |
| // Pros: Clean, readable, SSR | |
| // Con: Not universal (no vite, event handling) | |
| // export default async function Test() { | |
| // const response = await fetch(URL) | |
| // const data = await response.json() | |
| // return ( | |
| // <> | |
| // <h1>Dog App</h1> | |
| // <div>Here is a picture of a dog:</div> | |
| // <img src={data.message} width={300} /> | |
| // </> | |
| // ) | |
| // } | |
| // V4 - event handling | |
| // Pros: Universal, Clean, readable | |
| // Cons: No SSR, requires user interaction | |
| // export default function Test() { | |
| // const [result, setResult] = useState<Result>() | |
| // return ( | |
| // <> | |
| // <h1>Dog App</h1> | |
| // <button | |
| // onClick={async () => { | |
| // const response = await fetch(URL) | |
| // const data = await response.json() | |
| // setResult(data) | |
| // }} | |
| // > | |
| // Click for a new dog | |
| // </button> | |
| // {result | |
| // ? <img src={result?.message} width={300} /> | |
| // : <div>...</div> | |
| // } | |
| // </> | |
| // ) | |
| // } | |
| // export default function Test() { | |
| // const [result, setResult] = useState<Result>() | |
| // return ( | |
| // <> | |
| // <h1>Dog App</h1> | |
| // <button | |
| // onClick={async () => { | |
| // const response = await fetch(URL) | |
| // const data = await response.json() | |
| // setResult(data) | |
| // }} | |
| // > | |
| // Click for a new dog | |
| // </button> | |
| // {result | |
| // ? <img src={result?.message} width={300} /> | |
| // : <div>...</div> | |
| // } | |
| // </> | |
| // ) | |
| // } | |
| const IMAGE_URL = 'https://dog.ceo/api/breeds/image/random' | |
| async function getImage () { | |
| const response = await fetch(IMAGE_URL) | |
| const data = await response.json() | |
| return data.message | |
| } | |
| async function sleep (ms: number) { | |
| return new Promise((resolve) => setTimeout(resolve, ms)) | |
| } | |
| const BREEDS_URL = 'https://dog.ceo/api/breeds/list/all' | |
| async function getBreeds () { | |
| await sleep(5000) | |
| const response = await fetch(BREEDS_URL) | |
| const data = await response.json() | |
| const breeds = Object.keys(data.message) | |
| return breeds.slice(0, 10) | |
| } | |
| // V1.1 - load all data at the top level | |
| // Pros: Clean, readable, SSR | |
| // Cons: It waits for each download, so the loading times are added together (could avoid with Promise.all() | |
| // With Promise.all, the loading times aren't added together, but the whole page still has to wait for the slowest download | |
| // async function Test () { | |
| // // const image = await getImage() | |
| // // const breeds = await getBreeds() | |
| // const [image, breeds] = await Promise.all([getImage(), getBreeds()]) | |
| // return ( | |
| // <> | |
| // <h1>Dog App</h1> | |
| // <h2>Breeds</h2> | |
| // {breeds.map((breed) => ( | |
| // <button key={breed}>{breed}</button> | |
| // ))} | |
| // <h2>Image</h2> | |
| // <img src={image} width={300} /> | |
| // </> | |
| // ) | |
| // } | |
| // V1.2 - load data in parallel with suspense | |
| // Pros: Clean, readable, SSR, it lets the fast parts load fast | |
| // Cons: A bit weird, because you need Suspense, and you have to break into smaller components, and I guess we're just not used it and normally we only actually have one download, or all the downloads are fast, or at least equally fast, so there's not really that much point | |
| // Robots will only see the data from the first download, not the slowers ones | |
| async function Breeds () { | |
| const breeds = await getBreeds() | |
| return ( | |
| <> | |
| {breeds.map((breed) => ( | |
| <button key={breed}>{breed}</button> | |
| ))} | |
| </> | |
| ) | |
| } | |
| async function Dog () { | |
| const image = await getImage() | |
| return <img src={image} width={300} /> | |
| } | |
| export default async function Test () { | |
| return ( | |
| <> | |
| <h1>Dog App</h1> | |
| <h2>Breeds</h2> | |
| <Suspense fallback={<div>Loading breeds...</div>}> | |
| <Breeds /> | |
| </Suspense> | |
| <h2>Image</h2> | |
| <Suspense fallback={<div>Loading image...</div>}> | |
| <Dog /> | |
| </Suspense> | |
| </> | |
| ) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment