Teachnique
      CourseRoadmaps
      Login

      Introduction

      Project SetupCLI

      IntroductionAPP RouterTemplateLoading UIError Handling404 Page

      Linking and Navigating

      Dynamic RoutesRoute groupsParallel RoutesIntercepting Routes

      Route handlersCacheCommon Questions

      Middleware

      CSRSSR & SSGISR

      React Server ComponentsServer-Side Rendering

      SuspenseStreaming

      Server & Client ComponentServer vs. Client ComponentBest Practices

      Server-Side Rendering Strategies

      Data Fetching & Caching & RedirectThird-Party Request Libraries on the Server SideBest Practices

      Request MemoizationData CacheFull Route CacheRouter Cache

      Server Actions IFormServer Actions IIOptimistic Update

      Tailwind CSSCSS-in-JSSass

      Environment VariablesAbsolute Imports& Module Path AliasesRoute Segment Config

      Image & LCPImage IImage IIOptimizing IOptimizing II

      Next FontFont ParameterApply Styles

      Feedback

      Submit request if you have any questions.

      Course
      Loading UI

      Next.js Mastery: From Fundamentals to Full-Stack

      Unlock the power of Next.js with this comprehensive course! Starting with the basics, you’ll learn essential skills such as routing, data fetching, and styling. Progress through practical projects, including building your own React Notes app, to gain hands-on experience. Dive into the source code to understand the inner workings and core principles of Next.js. Perfect for developers with a basic knowledge of React and Node.js, this course ensures you’ll be ready to create high-performance full-stack applications efficiently. Join us and master Next.js, backed by industry experts and a supportive learning community.

      Loading UI


      
      Now that we have a grasp of the functionalities of page.js, layout.js, and template.js, let's consider some other important files. One such file is loading.js, provided by the App Router to display a loading UI.
      
      This file utilizes React's Suspense API. For more on this, refer to the article React's Suspense documentation. When a route changes, it immediately shows a fallback UI and then displays the data once it's loaded.
      <Suspense fallback={<Spinner />}>
      <ProfilePage />
      </Suspense>
      
      A common question with Suspense is, "How do we control the closing of the fallback UI?"
      Even React's documentation doesn't delve deeply into this. The logic is simple: ProfilePage throws a data-loading promise, which Suspense captures and appends a then function to. This function replaces the fallback UI. Once the data loads and the promise resolves, the then function executes, updating the UI.
      
      Let's see how to write loading.js. Create a loading.js file in the dashboard directory:
      
      // app/dashboard/loading.js
      export default function DashboardLoading() {
      return (
      <div className="flex items-center justify-center mt-40">
      <h1 className="text-3xl">Loading...</h1>
      </div>
      );
      }
      
      
      Here's the code for page.js at the same level:
      // app/dashboard/page.js
      async function getData() {
      await new Promise((resolve) => setTimeout(resolve, 3000));
      return {
      message: 'Hello, Dashboard!',
      };
      }
      
      export default async function Page() {
      const { message } = await getData();
      
      return (
      <div className="flex items-center justify-center mt-40">
      <h1 className="text-3xl">{message}</h1>
      </div>
      );
      }
      
      No additional code is needed to achieve the loading effect:
      

      Playground


      
      
      
      The key is that page.js exports an async function. The implementation of loading.js wraps page.js and its children in <Suspense>. Because page.js exports an async function, Suspense captures the data-loading promise, allowing the loading component to close appropriately.
      
      To implement a loading effect, exporting an async function is not the only method. You can also use React's use function.
      // /dashboard/page.js
      import { use } from 'react'
      
      async function getData() {
      await new Promise((resolve) => setTimeout(resolve, 3000))
      return {
      message: 'Hello, Dashboard!',
      }
      }
      
      export default function Page() {
      const { message } = use(getData())
      return (
      <div className="flex items-center justify-center mt-40">
      <h1 className="text-3xl">{message}</h1>
      </div>
      );
      }
      
      This also achieves the loading effect:
      
      If you want a specific loading effect for /dashboard/about, create another loading.js in the about directory.
      If a folder contains layout.js, template.js, and loading.js, what is their hierarchy?
      
      This diagram clarifies their hierarchy: