Course outline · 0% complete

0/29 lessons0%

Course overview →

Loading and error states

lesson 4-3 · ~9 min · 13/29

loading.js: the instant fallback

If app/blog/page.js takes two seconds to fetch, what does the user see meanwhile? Without help: the old page, frozen. Next.js fixes this with another special file:

// app/blog/loading.js
export default function Loading() {
  return <p>Loading posts…</p>;
}

Drop it next to page.js and Next.js shows it immediately on navigation, then streams in the real page when the data resolves. Under the hood this is React <Suspense>, wired up by the file convention. In the React course you managed loading flags by hand. Here the router does it for the whole page.

click~0 msdata readyloading.jsreal page.jsthe skeleton shows instantly, the page streams in when its data resolves
With loading.js in place, navigation shows the fallback immediately while the async page renders, then the finished content streams in.

error.js: the safety net

When a page throws (the API is down, the JSON is malformed), the matching error.js renders instead of a crash:

// app/blog/error.js
"use client";

export default function Error({ error, reset }) {
  return (
    <div>
      <p>Something went wrong.</p>
      <button onClick={reset}>Try again</button>
    </div>
  );
}

Two details to decode:

  • error.js must be a client component. It needs the onClick for reset, which re-attempts the render.
  • Like layouts, both files scope to their folder: an error.js in app/blog/ catches blog failures without touching the rest of the site.

Quiz

Why does error.js require the "use client" directive?

Problem

Your /dashboard page fetches slowly and users see nothing during navigation. Which special file do you add to app/dashboard/ to show an instant skeleton? (file name)