Next.js Dynamic & Catch-all Routes Sinhala Guide | Next.js රූට්ස්

Next.js Dynamic & Catch-all Routes Sinhala Guide | Next.js රූට්ස්

ආයුබෝවන් යාළුවනේ!

අද අපි කතා කරන්න යන්නේ Next.js වලින් Dynamic Routes සහ Catch-all Routes හසුරුවන්නේ කොහොමද කියන එක ගැන. මේක Next.js වලදී අපිට ගොඩක්ම අවශ්‍ය වෙන දෙයක්, මොකද අපේ වෙබ්සයිට් එකේ තියෙන ගොඩක් පිටු වලට එකම Layout එකයි, Component එකයි පාවිච්චි කරලා, ඩේටා විතරක් වෙනස් කරලා පෙන්වන්න පුළුවන්කම ලැබෙනවා.

උදාහරණයක් විදියට, බ්ලොග් එකක් හදනකොට හැම බ්ලොග් පෝස්ට් එකකටම වෙනම ෆයිල් එකක් හදන්න බෑනේ. ඒ වගේ වෙලාවට /blog/first-post, /blog/second-post වගේ URL වලට එකම [slug].js වගේ ෆයිල් එකක් පාවිච්චි කරලා, slug එක අනුව ඩේටා ටික වෙනස් කරලා පෙන්වන්න පුළුවන්. ඒ වගේම /docs/getting-started/installation වගේ ගැඹුරු URL path හසුරුවන්න Catch-all Routes අපිට උදව් වෙනවා.

මේ ටියුටෝරියල් එකෙන් අපි මොනවද ඉගෙන ගන්නේ?

  • Next.js වල සාමාන්‍ය Dynamic Routes ([slug], [id] වගේ) කියන්නේ මොනවද කියලා.
  • ඒවා හදාගන්නේ කොහොමද සහ useRouter එකෙන් Route Parameters ගන්න හැටි.
  • Catch-all Routes ([...slug]) කියන්නේ මොනවද සහ ඒවා පාවිච්චි කරන්නේ මොන වගේ අවස්ථාවලටද කියලා.
  • Next.js Route Matching Order එක වැඩ කරන්නේ කොහොමද කියලා.
  • ඒ වගේම, මේවා පාවිච්චි කරනකොට අවධානය යොමු කළ යුතු Best Practices සහ ඇතිවෙන්න පුළුවන් Common Issues.

එහෙනම්, අපි පටන් ගමු!

Next.js Dynamic Routes: මූලික සංකල්පය (Basic Concepts of Dynamic Routes)

Next.js වලදී Dynamic Routes කියන්නේ URL එකේ කොටසක් Run-time එකේදී වෙනස් වෙන Page එකක් හදාගන්න පුළුවන් ක්‍රමයක්. අපි මේවා හදන්නේ pages ෆෝල්ඩර් එක ඇතුලේ [] (square brackets) පාවිච්චි කරලා.

උදාහරණයක් විදියට, අපිට බ්ලොග් පෝස්ට් එකක් තියෙනවා නම්, හැම පෝස්ට් එකකටම වෙන වෙනම .js ෆයිල් එකක් හදන්නේ නැතුව, pages/posts/[slug].js වගේ ෆයිල් එකක් හදන්න පුළුවන්. [slug] කියන්නේ Route Parameter එක. මේකේ slug කියන නම වෙනුවට id, category වගේ ඕනෑම නමක් අපිට දාන්න පුළුවන්.

Dynamic Route එකක් හදාගන්නේ කොහොමද?

අපි හිතමු අපිට /posts/first-post, /posts/second-post වගේ URL එකකින් පෝස්ට් එකක් බලන්න ඕන කියලා. ඒකට pages ෆෝල්ඩර් එක ඇතුලේ posts කියන ෆෝල්ඩර් එක හදලා, ඒක ඇතුලේ [slug].js කියන ෆයිල් එක හදන්න ඕන.

// pages/posts/[slug].js

import { useRouter } from 'next/router';

function Post() {
  const router = useRouter();
  const { slug } = router.query; // URL එකෙන් slug එක ගන්නවා

  // router.query object එක ready වෙන්න පොඩි වෙලාවක් යන නිසා,
  // මුලින්ම slug එක undefined වෙන්න පුළුවන්. ඒක handle කරන්න ඕන.
  if (!router.isReady) {
    return <p>Loading...</p>;
  }

  return (
    <div>
      <h1>This is a Dynamic Post Page</h1>
      <p>The current slug is: <strong>{slug}</strong></p>
      <p>Here you would fetch data for <code>{slug}</code> from an API.</p>
    </div>
  );
}

export default Post;

මේ [slug].js ෆයිල් එකට /posts/first-post කියලා ගියොත්, slug එක විදියට first-post කියන එක ලැබෙනවා. /posts/another-post-title කියලා ගියොත් another-post-title එක ලැබෙනවා. අපි useRouter hook එක පාවිච්චි කරලා slug එක ගන්නේ router.query object එකෙන්. router.isReady පාවිච්චි කරන්නේ query object එක Ready ද කියලා බලන්න, මොකද Client-side navigation වලදී query object එක මුලින් හිස් වෙන්න පුළුවන්.

Catch-all Routes: වඩාත් නම්‍යශීලී Routes (More Flexible Routes with Catch-all)

සමහර වෙලාවට අපිට URL එකේ ඕනෑම කොටසක් Route Parameter එකක් විදියට ගන්න සිද්ධ වෙනවා. උදාහරණයක් විදියට, Documentation Section එකක් හදනකොට /docs/getting-started/installation, /docs/api-reference/users/get-all වගේ ගැඹුරු URL Path එන්න පුළුවන්. සාමාන්‍ය Dynamic Routes වලින් මේ වගේ එකකට එක Parameter එකයි ගන්න පුළුවන්. නමුත්, Catch-all Routes වලින් අපිට මේ වගේ බහුවිධ කොටස් Parameter Array එකක් විදියට ගන්න පුළුවන්.

Catch-all Routes හදන්නේ [...slug] (නැත්නම් [...paramName]) වගේ පාවිච්චි කරලා. මේකේ ... (spread operator) එකෙන් කියවෙන්නේ ඒ ස්ථානයෙන් පස්සේ එන හැම URL කොටසක්ම අර Parameter එකට Array එකක් විදියට ගන්න කියලා.

Catch-all Route එකක් හදාගන්නේ කොහොමද?

අපි හිතමු අපිට Documentation Page එකක් තියෙනවා කියලා. ඒකට pages/docs/[...slug].js වගේ ෆයිල් එකක් හදන්න පුළුවන්.

// pages/docs/[...slug].js

import { useRouter } from 'next/router';

function DocPage() {
  const router = useRouter();
  const { slug } = router.query; // URL එකෙන් slug Array එක ගන්නවා

  if (!router.isReady) {
    return <p>Loading...</p>;
  }

  // slug කියන එක Array එකක් විදියට අපිට ලැබෙනවා
  // උදා: /docs/a/b/c => slug = ['a', 'b', 'c']

  return (
    <div>
      <h1>Documentation Page</h1>
      <p>The current path segments are:</p>
      <ul>
        {slug && slug.map((segment, index) => (
          <li key={index}><strong>{segment}</strong></li>
        ))}
      </ul>
      <p>You can use these segments to fetch specific documentation content.</p>
    </div>
  );
}

export default DocPage;

මේ [...slug].js ෆයිල් එකට,

  • /docs/getting-started කියලා ගියොත්, slug එක ['getting-started'] විදියට ලැබෙනවා.
  • /docs/api-reference/users කියලා ගියොත්, slug එක ['api-reference', 'users'] විදියට ලැබෙනවා.
  • /docs/api-reference/users/get-all කියලා ගියොත්, slug එක ['api-reference', 'users', 'get-all'] විදියට ලැබෙනවා.

මේ Array එක පාවිච්චි කරලා අපිට Database එකෙන් හරි, Markdown Files වලින් හරි අදාළ Content එක Load කරගන්න පුළුවන්.

Optional Catch-all Routes (විකල්ප Catch-all Routes)

සමහර වෙලාවට අපිට /docs වගේ Root Path එකටත් /docs/getting-started වගේ ගැඹුරු Path වලටත් එකම Component එක පාවිච්චි කරන්න ඕන වෙනවා. මේකට Optional Catch-all Routes පාවිච්චි කරන්න පුළුවන්. මේවා හදන්නේ [[...slug]] වගේ, තව [] (square brackets) දෙකක් දාලා.

// pages/docs/[[...slug]].js

import { useRouter } from 'next/router';

function OptionalDocPage() {
  const router = useRouter();
  const { slug } = router.query;

  if (!router.isReady) {
    return <p>Loading...</p>;
  }

  // /docs => slug is undefined
  // /docs/a => slug = ['a']
  // /docs/a/b => slug = ['a', 'b']

  return (
    <div>
      <h1>Optional Documentation Page</h1>
      {slug ? (
        <div>
          <p>The current path segments are:</p>
          <ul>
            {slug.map((segment, index) => (
              <li key={index}><strong>{segment}</strong></li>
            ))}
          </ul>
        </div>
      ) : (
        <p>This is the root of the documentation.</p>
      )}
      <p>Content will vary based on path.</p>
    </div>
  );
}

export default OptionalDocPage;

මේ වගේ [[...slug]].js ෆයිල් එකක් තියෙනකොට, /docs කියලා ගියොත් slug එක undefined විදියට ලැබෙනවා. ඒක අපිට if (!slug) වගේ Check කරලා Default content එකක් පෙන්වන්න පුළුවන්.

Route Matching Order: Routes ගැටෙන හැටි (How Routes Collide)

Next.js වලට Page එකක් Load කරන්න ඕන වුණාම, URL Path එකට ගැලපෙන Route එක හොයන්නේ නිශ්චිත පිලිවෙලකට. මේක දැනගෙන ඉන්න එක ගොඩක් වැදගත්, මොකද නැත්නම් අපේ Routes එකට එකක් ගැටෙන්න පුළුවන්.

Next.js වල Route Matching Order එක මේ වගේ:

  1. Static Routes: pages/about.js, pages/posts/index.js වගේ ස්ථාවර Routes වලට මුලින්ම priority ලැබෙනවා.
  2. Dynamic Routes: pages/posts/[slug].js වගේ Dynamic Routes වලට දෙවනුව priority ලැබෙනවා.
  3. Catch-all Routes: pages/[...slug].js වගේ Catch-all Routes වලට අන්තිමට priority ලැබෙනවා.
  4. Optional Catch-all Routes: pages/[[...slug]].js වගේ ඒවා, Catch-all වගේම වැඩ කරනවා, නමුත් Root path එකටත් ගැලපෙනවා.

මේක තේරුම් ගන්න උදාහරණයක් බලමු:

අපිට මේ වගේ ෆයිල් Structure එකක් තියෙනවා කියලා හිතමු:

  • pages/blog/index.js
  • pages/blog/first-post.js
  • pages/blog/[slug].js
  • pages/blog/[...all].js

දැන්,

  • /blog කියන URL එකට යන්නේ pages/blog/index.js. (Static)
  • /blog/first-post කියන URL එකට යන්නේ pages/blog/first-post.js. (Static, Dynamic එකට වඩා priority වැඩියි)
  • /blog/my-blog-post කියන URL එකට යන්නේ pages/blog/[slug].js. (Dynamic)
  • /blog/category/sub-category කියන URL එකට යන්නේ pages/blog/[...all].js. (Catch-all)

මේකෙන් තේරෙන්නේ, static route එකක් තියෙනවා නම්, ඒකට priority එක ලැබෙනවා. ඊට පස්සේ dynamic route එකකට, ඊටත් පස්සේ catch-all route එකකට. ඒ නිසා [slug].js වගේ Dynamic Route එකක් තියෙන ෆෝල්ඩර් එකකම [...slug].js වගේ Catch-all Route එකක් තියෙනවා නම්, ගැටළු ඇතිවෙන්න පුළුවන්. සාමාන්‍යයෙන් Catch-all Routes දාන්නේ වෙන කිසිම Route එකක් match නොවෙන අවස්ථාවලටයි.

Best Practices සහ සාමාන්‍යයෙන් එන ගැටළු (Best Practices & Common Issues)

1. Catch-all Routes පාවිච්චි කරන එක ගැන සැලකිලිමත් වෙන්න (Use Catch-all Routes Sparingly)

Catch-all Routes ගොඩක් flexible වුණාට, ඒවා නිතරම පාවිච්චි කරන එක හොඳ නැහැ. මොකද ඒවා ඕනෑම URL එකක් Match කරන්න පුළුවන් නිසා, අපිට Control එකක් නැති වෙන්න පුළුවන්. Documentations, knowledge bases, හෝ user-defined content paths වගේ පැහැදිලි භාවිත අවස්ථා වලට විතරක් මේවා පාවිච්චි කරන්න.

2. Parameter Validation (පැරාමීටර වලංගු කරන්න)

URL එකෙන් එන Route Parameters හැමවිටම අපි බලාපොරොත්තු වෙන Format එකටම නැති වෙන්න පුළුවන්. ඒ නිසා, slug, id වගේ Parameters පාවිච්චි කරනකොට, ඒවා නිවැරදිද, අපිට අවශ්‍ය Format එකට තියෙනවද කියලා Validate කරන්න ඕන. Regular Expressions (RegEx) පාවිච්චි කරලා හෝ Data type check කරලා මේක කරන්න පුළුවන්.

import { useRouter } from 'next/router';

function BlogPost() {
  const router = useRouter();
  const { slug } = router.query;

  if (!router.isReady) {
    return <p>Loading...</p>;
  }

  // Simple validation example
  if (typeof slug !== 'string' || slug.length === 0) {
    return <p>Invalid blog post slug.</p>;
  }

  // Fetch data based on valid slug
  // ...
  return (
    <div>
      <h1>Blog Post: {slug}</h1>
      <!-- Content here -->
    </div>
  );
}

3. Client-side Navigation සහ `router.isReady` (Client-side Navigation and `router.isReady`)

Next.js වල <Link> component එකෙන් හෝ router.push() වලින් Client-side navigation කරනකොට, මුලින්ම router.query object එක හිස් වෙන්න පුළුවන්. isReady කියන Property එක true වෙනකම් router.query එකේ අගයන් නැතිවෙන්න පුළුවන්. ඒ නිසා, router.query එක පාවිච්චි කරනකොට if (!router.isReady) { return <p>Loading...</p>; } වගේ Check එකක් දාන එක හොඳ practice එකක්.

4. Static Site Generation (SSG) සහ Server-Side Rendering (SSR) එක්ක (With SSG and SSR)

Dynamic Routes පාවිච්චි කරනකොට getStaticProps, getStaticPaths, getServerSideProps වගේ Next.js Data Fetching Functions එක්ක වැඩ කරන හැටි දැනගෙන ඉන්න එක ගොඩක් වැදගත්.

  • getStaticProps සහ getStaticPaths: Static Generate කරන්න පුළුවන් Dynamic Routes වලට මේවා පාවිච්චි කරනවා. getStaticPaths වලින් අපි Build Time එකේදී හදන්න ඕන URL Paths ටික specify කරනවා.
  • getServerSideProps: හැම Request එකකටම Server එකේදී Data Fetch කරන්න ඕන Dynamic Routes වලට මේක පාවිච්චි කරනවා.

මේවා ගැන තව විස්තර වෙනම ටියුටෝරියල් එකකින් බලමු, නමුත් දැනට මතක තියාගන්න, Dynamic Routes වල Performance optimize කරන්න මේවා ගොඩක් වැදගත් කියලා.

නිගමනය (Conclusion)

ඉතින් යාළුවනේ, Next.js වල Dynamic Routes සහ Catch-all Routes ගැන ඔබට පැහැදිලි අවබෝධයක් ලැබෙන්න ඇති කියලා මම හිතනවා. මේවා Next.js Framework එකේ තියෙන බලවත්ම Features දෙකක්, මොකද ඒවා අපිට scalable සහ maintain කරන්න පහසු වෙබ් ඇප්ලිකේෂන් හදන්න ගොඩක් උදව් වෙනවා.

  • සාමාන්‍ය Dynamic Routes ([slug]) වලින් එක Parameter එකක් ගන්න පුළුවන්.
  • Catch-all Routes ([...slug]) වලින් Array එකක් විදියට ඕනෑම ගානක් Parameter ගන්න පුළුවන්.
  • Optional Catch-all Routes ([[...slug]]) වලින් Root Path එකටත් Match කරන්න පුළුවන්.
  • Route Matching Order එක තේරුම් ගන්න එක ගැටුම් වළක්වා ගැනීමට වැදගත්.
  • ඒ වගේම, useRouter().query එක පාවිච්චි කරනකොට router.isReady Check එක දාන්න අමතක කරන්න එපා.

මේ Concepts ටික තේරුම් අරන්, ඔයාලගේ Next.js Projects වලට මේවා implement කරලා බලන්න. මොකද, theory විතරක් මදි, practice කරන එක ගොඩක් වැදගත්!

ඔබට මේ ගැන තව ප්‍රශ්න තියෙනවා නම්, නැත්නම් මේක ගැන ඔයාලගේ අත්දැකීම් කොහොමද කියලා කියන්න කැමති නම්, පහලින් Comment එකක් දාන්න. අපි ඊළඟ ටියුටෝරියල් එකෙන් හම්බවෙමු! සුභ දවසක්!