3. Loading UI , Data fetching - Next.JS

Ayush RajputAyush Rajput
3 min read
  1. Loading UI with React suspense component.

    React Suspense : Suspense is a React component that lets you "wait" for some part of the component tree to load or resolve, and while it's doing that, it renders a fallback UI (like a loader).

    File Structure :

     app/
     ├── layout.js         # Root layout for the entire app
     ├── loading.js        # Global fallback loading UI
     ├── page.js           # Your homepage or main route
     ├── globals.css       # Global styles
    

    In loading.js -

// app/loading.js
export default function Loading() {
  return <h1 className="text-5xl">Loading ....</h1>;
}
//This will be used as the fallback UI when components are streaming or waiting for data/code.

In Layout .js -

// app/layout.js
import { Suspense } from "react";
import Loading from "./loading";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <Suspense fallback={<Loading />}>
          {children}
        </Suspense>
      </body>
    </html>
  );
}

What This Does:

  • Wraps your entire app in a Suspense boundary.

  • Whenever a child component under this layout is:

    • Async

    • Lazy-loaded

    • Server-rendered with delay then it will temporarily render <Loading /> instead, until the content is ready.

  1. Server side data fetching

    Data is fetched on the server (Node.js) before the page is sent to the browser.

    💡 When to Use:

    • SEO is important (search engines should see content)

    • Sensitive data (tokens, DB calls)

    • You want fast initial page loads

    • You use a CMS or backend API

    // /app/server-example/page.js

    async function fetchUsers() {
      const res = await fetch('https://dummyjson.com/users');
      const data = await res.json();
      return data.users;
    }

    export default async function ServerPage() {
      const users = await fetchUsers(); // ✅ Server fetch
      return (
        <div>
          <h1>Server-Side Rendered User List</h1>
          <ul>
            {users.map((user) => (
              <li key={user.id}>{user.firstName}</li>  // this id will extract using params in userDetail page
            ))}
          </ul>
        </div>
      );
    }

Behind the Scenes:

  • This runs on the server (not browser)

  • HTML is pre-rendered with full data

  • Delivered to browser

  • Blazing fast

✅ Pros:

  • ✅ Great for SEO

  • ✅ Fast initial load

  • ✅ Can use secure tokens (not exposed to browser)

  • ✅ Full SSR (server-side rendering)

❌ Cons:

  • ❌ Not interactive on fetch failure (page breaks)

  • ❌ Can’t use browser-only features like localStorage, window

  1. Client side data fetching

    The page is sent without data, and then data is fetched from the browser (client) using useEffect() or libraries like SWR, Axios, Fetch, etc.

    💡 When to Use:

    • SEO is not critical

    • Data changes frequently

    • You need to show spinners, loaders, etc.

    • Logged-in user dashboards (browser-only)

// /app/client-example/page.js
'use client';
import { useEffect, useState } from "react";
export default function ClientPage() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('https://dummyjson.com/users')
      .then(res => res.json())
      .then(data => {
        setUsers(data.users);
        setLoading(false);
      });
  }, []);

  return (
    <div>
      <h1>Client-Side Rendered Users</h1>
      {loading ? (
        <p>Loading...</p>
      ) : (
        <ul>
          {users.map(user => (
            <li key={user.id}>{user.firstName}</li>
          ))}
        </ul>
      )}
    </div>
  );
}

⚙️ Behind the Scenes:

  • Loads blank page initially

  • Then fetches data via browser

  • Shows loading indicator


✅ Pros:

  • ✅ Can interact with browser (window, localStorage)

  • ✅ Good for dynamic dashboards

  • ✅ Can use spinners/loaders nicely

❌ Cons:

  • ❌ Bad for SEO

  • ❌ Slow first load (data comes after)

  • ❌ No SSR

  1. Data fetching with SWR(Client Side, Better UX)

'use client';
import useSWR from 'swr';

const fetcher = (...args) => fetch(...args).then(res => res.json());

export default function WithSWR() {
  const { data, error, isLoading } = useSWR('https://dummyjson.com/users', fetcher);

  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error fetching data!</p>;

  return (
    <ul>
      {data.users.map((u) => (
        <li key={u.id}>{u.firstName}</li>
      ))}
    </ul>
  );
}
0
Subscribe to my newsletter

Read articles from Ayush Rajput directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ayush Rajput
Ayush Rajput