Галоўная / Артыкулы / Едынаклі источнік правды для маршрутаў у прыемплявах Next.js

Едынаклі источнік правды для маршрутаў у прыемплявах Next.js

Дазвольце дазнаць, як модуль центральных маршрутаў, створаны за дапамой типавання, заменяе розрозненыя шляхі у вигляде стрынгаў у Next.js, за дапамогою функцый-падказчыкаў для дынамічных сегментаў і групавання экспорта маршрутаў.

1222 слоў

Большасць проектаў на Next.js пачынаюцца з прымусовага вводу шляхоў безпасцередна ў компоненты Link і вызывы router.push. Гэта шырока для першых калькі сторанак, але калі прыложэнне растае, тыя ж самыя строкі павтараюцца ў навігацыяных панелях, футерах, перенаправленнях і электронных пісьмох, і кожная замена назвы стае задачай пошуку та замены. Проблема паглыбляецца, калі асистэнты для напісання коду на AI генеруюць частку коду, адтолькі як яны рэдка калі дотрымваюцца адной і той жа конвэнціі настойчыва. Перанесенне всіх шляхоў у адны модуль з вводам рашае гэту проблему.

Што паследзіць з інлайн-шляхамі

Ёсць тыповы компонент навігацыі, дзе кожна пунктазначэння ўособлівае ся як строка:

// ❌ Problematic approach

import Link from 'next/link'
import { useRouter } from 'next/router'

export default function Navbar() {
  const router = useRouter()

  const handleNavigation = () => {
    router.push('/dashboard/user/profile')
  }

  return (
    <nav>
      <Link href="/about">About</Link>
      <Link href="/contact">Contact</Link>
      <Link href="/blog">Blog</Link>
      <Link href="/dashboard/analytics">Analytics</Link>
      <button onClick={handleNavigation}>Profile</button>
    </nav>
  )
}

Сёньдзе тут нічога не зламана, але чатыры проблемы выявляюцца ў меру росту базы коду та каманды.

Замены назв стаюць складным задачам

Змена /blog на /articles абярае пошук усіх прыкладоў ў компанентах, коде сервера, тэстах і настройках. Якшто ўпусціць адны, застаецца недзейная лінк.

Памылкі напісу застаюцца

Такі шлях як /dashbord — гэта проста строка, таму ні кампайляр, ні інструменты для перагледу коду яе не спраўляюць. Памылка зазвычай выявляецца як код 404, інодзе толькі ў режыме продакшна.

Рэдагар не можа дапамогчы

Пакалі маршруты — гэта неструктураваныя строкі, то немае автодаполнення, немае возможнасці «перайсці да вызначэння», і немае паведамлення, калі маршрут больш не існуе.

Члэны команды раз'яўляюцца

Разныя людзі і разныя запросы для ШІ ў канцэ нарабляюць той самы пункт назначэння адносна разнымі спосабамі: з канцоўкай слэша або без яе, з ручна створаным шаблонам запита і так далей.

Цэнтрызаванне маршрутаў у адным модуле

Рашэнь — это адзін файл настройкаў, які імпортуецца кожным часткам прыёмніка.

Дзе знаходзіцца файл

Папка constants або config, якая знаходзіцца празаўсёды ля app і components, дапамагае лёгка ўсё знайсці:

/src
  /app
  /components
  /constants
    └── routes.ts
  /lib

Адзначэнне об’екта маршрутаў

Модуль нижэй групавае маршруты па зонам. Статычныя сторанкі — это простыя строкі. Дынамічныя сторанкі — это маленькія функцыі, якія прымоўнаюць зменную сегмент і вяртаюць полны шлях, таму вызываючыя апранткі ніколі не складаюць URL-адрэсы вручную. Канцэнтры API знаходзяцца пад вкладанай ключоўкой API для выкарыстоўвання ў вызовах fetch. Адзначэнне as const дапамагае TypeScript адгадваць точныя літэральныя значэнні і пазначае об’ект як толькі для чытання, што дазволяе точнае автодаполненне і запобегае випадковай перэзначэнню.

// constants/routes.ts
export const ROUTES = {
  // Public routes
  HOME: '/',
  ABOUT: '/about',
  CONTACT: '/contact',
  PRICING: '/pricing',

  // Auth routes
  LOGIN: '/auth/login',
  REGISTER: '/auth/register',
  FORGOT_PASSWORD: '/auth/forgot-password',

  // Blog routes
  BLOG: '/blog',
  BLOG_DETAIL: (slug: string) => `/blog/${slug}`,
  BLOG_CATEGORY: (category: string) => `/blog/category/${category}`,

  // Dashboard routes
  DASHBOARD: '/dashboard',
  DASHBOARD_ANALYTICS: '/dashboard/analytics',
  DASHBOARD_SETTINGS: '/dashboard/settings',
  DASHBOARD_PROFILE: '/dashboard/profile',

  // Dynamic user routes
  USER_PROFILE: (userId: string) => `/user/${userId}`,
  USER_POSTS: (userId: string) => `/user/${userId}/posts`,

  // API routes (useful for fetch calls)
  API: {
    USERS: '/api/users',
    POSTS: '/api/posts',
    AUTH: '/api/auth',
  },
} as const

// Export route groups for better organization
export const AUTH_ROUTES = {
  LOGIN: ROUTES.LOGIN,
  REGISTER: ROUTES.REGISTER,
  FORGOT_PASSWORD: ROUTES.FORGOT_PASSWORD,
} as const

export const DASHBOARD_ROUTES = {
  HOME: ROUTES.DASHBOARD,
  ANALYTICS: ROUTES.DASHBOARD_ANALYTICS,
  SETTINGS: ROUTES.DASHBOARD_SETTINGS,
  PROFILE: ROUTES.DASHBOARD_PROFILE,
} as const

Два дадзеных экспорта, AUTH_ROUTES і DASHBOARD_ROUTES, являюцься відбірамі з галоўнага об’екта для коду, якій не патрэбны іншыя роздзелы, напрыклад, для мідлвэра, який захоўвае панель керування. Паколькі ў яных выкарыстоўваецца ROUTES, а не павтарэння страк, за кожным шляхам застаецца толькі адна вялічына.

Аднай з удосконаленняў, якія варта рассмотрзець, ёсць наступная: якщо ідэнтыфікатор або ID можа мець прасловы чы спецыяльныя знакі, яго трэба загорнуць у encodeURIComponent у рамках дапаможнага функцыі, каб кожны корыстувач апошнюючы трымаў безпечны URL.

Іспытанне шляхоў у компонентах

Тепер navbar імпортуе імены заместо страк. Як Link, так і імператыўная навігацыя чытаюць данні з таго ж модуля, таму яны ніколі не можаць суперсечыцца:

// components/Navbar.tsx
import Link from 'next/link'
import { useRouter } from 'next/router'
import { ROUTES, DASHBOARD_ROUTES } from '@/constants/routes'

export default function Navbar() {
  const router = useRouter()

  const handleProfileNavigation = () => {
    router.push(DASHBOARD_ROUTES.PROFILE)
  }

  return (
    <nav className="flex space-x-4">
      <Link href={ROUTES.ABOUT} className="hover:text-blue-500">
        About
      </Link>
      <Link href={ROUTES.CONTACT} className="hover:text-blue-500">
        Contact
      </Link>
      <Link href={ROUTES.BLOG} className="hover:text-blue-500">
        Blog
      </Link>
      <Link href={DASHBOARD_ROUTES.ANALYTICS} className="hover:text-blue-500">
        Analytics
      </Link>
      <button
        onClick={handleProfileNavigation}
        className="rounded bg-blue-500 px-4 py-2 text-white"
      >
        Profile
      </button>
    </nav>
  )
}

Заўважкі: у гэтым прыкладзе імпортуецца useRouter з next/router, які належыць да Pages Router. У проектах App Router яго трэба імпортуваць з next/navigation унутры кліентскага компонента; модуль routes працюе аднойчы так сама незалежна ад таго, куды ён імпортуецца.

Стварэнне дынамічных лінкаў

Дынамічныя сегменты — гэта там, дзе такі падход даўа максымальны эфект. У прыведзенай нижэй справаке є паўязкі на кожную пастацю і яе катэгорыю за дапамогою функцый-памочнікаў, якія прымаюць даны з пастаці:

// components/BlogList.tsx
import Link from 'next/link'
import { ROUTES } from '@/constants/routes'

interface Post {
  slug: string
  title: string
  category: string
}

interface BlogListProps {
  posts: Post[]
}

export default function BlogList({ posts }: BlogListProps) {
  return (
    <div className="space-y-4">
      {posts.map((post) => (
        <article key={post.slug} className="rounded border p-4">
          <h2 className="text-xl font-bold">
            <Link href={ROUTES.BLOG_DETAIL(post.slug)} className="hover:text-blue-500">
              {post.title}
            </Link>
          </h2>
          <Link
            href={ROUTES.BLOG_CATEGORY(post.category)}
            className="text-sm text-gray-500 hover:text-blue-500"
          >
            Category: {post.category}
          </Link>
        </article>
      ))}
    </div>
  )
}

Якщо структура URL для пастацяў калі-небудзь зменіцца, напрыклад, праз дадаўшы сегмент з годам, достатнья будзе адначасова апдэйтаваць BLOG_DETAIL, і ўсі вызывальнікі будуць яго следаваць. TypeScript таксама пакажа павестку пра будзь-які вызыв, у яком будзе некалькі аргументаў.

Што вы отрымваеце

  • Кожны шлях задаецца аднойчы і викорыстоўваецца ў всіх месцах.
  • Неправільна напісання назв маршрутав не дозволяе працэўваць праграме ў часе кампілявання, замест таго што падаюць коды 404.
  • Змена URL — це рэедыт у аднай лініі.
  • Структура застаецца арганізаванай, калі колькасць стороніц зрастае.
  • Рэдагувальнікі прысвячваюць функціі автодаполнення і пераканальвання датак для кожнай пунктазіі.
  • Тыя ж константы выкорыстоўваюцца для навігацыйных паліц, футэраў, сіт-картаў і паходжных пазнак.
  • Одны файл дае швыракі аптак усіх стороніц у працэўніку.
  • Ліміты і альтэрнатывы

    Файл з константамі не пераканальвае, чы рэальна сторонка, якая падходзіць, існуе ў каталогу app або pages. Якщо папка перайменовуецца без адкорэгавання модуля, галоўнікі застаюцца несправнымі. Next.js таксама прымае опцыю typed routes, якая генеруе типы з файловай системы; пераканальваецеся ў актуальной даследчыцкай документацыі ўсюго пра ее статус і чы яна падходзіць вашай наладзе. Багато командаў сумяшваюць абодве: генераваныя типы для правільнасці і модуль з константамі для чытабельных назваў і дапаможнікаў.

    Калі AI-асистэнты дапамагаюць у стварэнні коду, паведаміце ім у інструкцыях да вашага проекту, каб яны імпортавалі з модуля routes.

    Заключанне

    Спрыяйце URL-адрэсам даўаць ся як частка API вашага прыемлівальніка, а не як розрозненыя строкі. Типаваны, цэнтрызаваны модуль routes ператварае перайменоўванні на адзіныя змены, выяўляе памылкі ў рэдагувальніку і дае як людям, так і інструментам адзіны зрозумелы месца для пошуку.