60 Matching Annotations
  1. Last 7 days
  2. Mar 2023
    1. Streaming allows you to break down the page's HTML into smaller chunks and progressively send those chunks from the server to the client.

    1. ```js

      export const loader = async () => {

      // fire them all at once<br /> const critical1Promise = fetch('/test?text=critical1&delay=250').then(res => res.json()); const critical2Promise = fetch('/test?text=critical2&delay=500').then(res => res.json()); const lazyResolvedPromise = fetch('/test?text=lazyResolved&delay=100').then(res => res.json()); const lazy1Promise = fetch('/test?text=lazy1&delay=500').then(res => res.json()); const lazy2Promise = fetch('/test?text=lazy2&delay=1500').then(res => res.json()); const lazy3Promise = fetch('/test?text=lazy3&delay=2500').then(res => res.json()); const lazyErrorPromise = fetch('/test?text=lazy3&delay=3000').then(res => { throw Error('Oh noo!') });

      // await for the response return defer({ critical1: await critical1Promise, critical2: await critical2Promise, lazyResolved: lazyResolvedPromise, lazy1: lazy1Promise, lazy2: lazy2Promise, lazy3: lazy3Promise, lazyError: lazyErrorPromise }) } ```

    1. We present deferred data by using React Suspense to conditionally show the content when it's ready. Suspense provides a fallback element to show when the data is not yet ready. Normally a loading spinner would go here, but we can use that to show our streamed progress instead.

      js export default function Index() { const data = useLoaderData() const params = useParams() const stream = useEventSource( `/items/${params.hash}/progress`, { event: "progress", }, ) return ( <div> <Suspense fallback={<span> {stream}% </span>}> <Await resolve={data.promise} errorElement={<p>Error loading img!</p>} > {(promise) => <img alt="" src={promise.img} />} </Await> </Suspense> </div> ) }

    2. The loader defers a promise that will resolve only when the json's progress has hit 100.

      js export async function loader({ params }: LoaderArgs) { if (!params.hash) return redirect("/") const pathname = path.join( "public", "items", `${params.hash}.json`, ) const file = fs.readFileSync(pathname) if (!file) return redirect("/") const item = JSON.parse(file.toString()) if (!item) return redirect("/") if (item.progress === 100) { return defer({ promise: item, }) } return defer({ promise: new Promise((resolve) => { const interval = setInterval(() => { const file = fs.readFileSync(pathname) if (!file) return const item = JSON.parse(file.toString()) if (!item) return if (item.progress === 100) { clearInterval(interval) resolve(item) } return }) }), }) }

    3. Defer is a feature of Remix that allows you to return an unresolved Promise from a loader. The page will server-side render without waiting for the promise to resolve, and then when it finally does, the client will re-render with the new data.
    1. Suspense itself will show fallbacks when not ready and reveal the contents when promises resolve, problem is that if there are multiple Suspense components, it could lead to flickering because of the order is not assured, that’s why we need sorta coordinating. SuspenseList is exactly for this.



      <React.SuspenseList revealOrder="forwards"> <React.Suspense fallback={\<p>loading...\

      }> <Child resource={resource1} /> </React.Suspense> <React.Suspense fallback={\<p>loading...\

      }> <Child resource={resource2} /> </React.Suspense> <React.Suspense fallback={\<p>loading...\

      }> <Child resource={resource3} /> </React.Suspense> </React.SuspenseList> ```

      We can see that the revealing order is kept, from top to bottom, even though the 2nd promise if fulfilled sooner.

    1. Fortunately with webpackChunkName in an inline comment, we can instruct webpack to name the file something much friendlier.

      js const HeavyComponent = lazy(() => import(/* webpackChunkName: "HeavyComponent" */ './HeavyComponent');

    1. Similar to prefetching, you can specify the chunk name with an inline comment using the webpackChunkName key

      js const LazyLoad = lazy(() => import(/* webpackChunkName: 'lazyload' */ './LazyLoad') );

    2. For example, if the user is on the login page, you can load the post-login home page. An inline comment with the webpackPrefetch key within the dynamic import function will instruct Webpack to do just this.

      ```js const PrefetchLoad = lazy(() => import( / webpackPrefetch: true / './PrefetchLoad' ) );

      const App = () => { return ( <Suspense fallback="Loading"> {condition && <PrefetchLoad />} </Suspense> ); }; ```

    3. Now when App is rendered and a request is initiated to get the LazyLoad code, the fallback Loading is rendered. When this request completes, React will then render LazyLoad.

      js const App = () => { return ( <Suspense fallback="Loading"> <LazyLoad /> </Suspense> ); };

    1. You can have multiple nested React.lazy components inside React.Suspense.


      const CatAvatar = React.lazy(() => import('./path/to/cat/avatar')); const ThorAvatar = React.lazy(() => import('./path/to/cat/thor-avatar'));

      const AppContainer = () => ( <React.Suspense fallback="loading..."> <CatAvatar /> <ThorAvatar /> </React.Suspense> ); ```

  3. Feb 2023
  4. Oct 2021
  5. Sep 2020
    1. wait a little

      This is the third time that Sergeant Cuff is saying “Wait a little” to Betteredge. This phrase, although creating an aura of mystery/suspense, reminds me of the request at the beginning of the novel to the family to suspend judgment until the story is over (and thus maybe is a reminder to the reader?). However, the phrase is also kind of funny to me because at this point, “wait[ing] a little” to the audience really has the opposite effect, despite the suspense the phrase creates: instead of putting down the book and literally waiting, we actually want to keep reading. This makes me think that there might be an interesting way to measure suspense in literature (this one being some kind of technique through reverse psychology?)

  6. Jan 2020
  7. Aug 2019
    1. With Suspense, you have the ability to suspend component rendering while async data is being loaded. You can pause any state update until the data is ready, and you can add async loading to any component deep in the tree without plumbing all the props and state through your app and hoisting the logic.