Skip to main content

path-params

Dynamic path segments ($paramName), splat routes ($ / _splat), optional params ({-$paramName}), prefix/suffix patterns ({$param}.ext), useParams, params.parse/stringify, pathParamsAllowedCharacters, i18n locale patterns.

소스 정보

저장소
TanStack/router
최근 소스 활동
2026년 7월 26일 16:53
감지된 SKILL.md 언어
영어
스타
15,202
포크
1,900

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
path-params
description
Dynamic path segments ($paramName), splat routes ($ / _splat), optional params ({-$paramName}), prefix/suffix patterns ({$param}.ext), useParams, params.parse/stringify, pathParamsAllowedCharacters, i18n locale patterns.
metadata
{"type":"sub-skill","library":"tanstack-router","library_version":"1.171.15"}
requires
["router-core"]
sources
["TanStack/router:docs/router/guide/path-params.md","TanStack/router:docs/router/routing/routing-concepts.md","TanStack/router:docs/router/guide/internationalization-i18n.md"]
# Path Params Path params capture dynamic URL segments into named variables. They are defined with a `$` prefix in the route path. > **CRITICAL**: Never interpolate params into the `to` string. Always use the `params` prop. This is the most common agent mistake for path params. > **CRITICAL**: Types are fully inferred. Never annotate the return of `useParams()`. ## Dynamic Segments A segment prefixed with `$` captures text until the next `/`. ```tsx // src/routes/posts.$postId.tsx import { createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/posts/$postId')({ loader: async ({ params }) => { // params.postId is string — fully inferred, do not annotate return fetchPost(params.postId) }, component: PostComponent, }) function PostComponent() { const { postId } = Route.useParams() const data = Route.useLoaderData() return ( <h1> Post {postId}: {data.title} </h1> ) } ``` Multiple dynamic segments work across path levels: ```tsx // src/routes/teams.$teamId.members.$memberId.tsx export const Route = createFileRoute('/teams/$teamId/members/$memberId')({ component: MemberComponent, }) function MemberComponent() { const { teamId, memberId } = Route.useParams() return ( <div> Team {teamId}, Member {memberId} </div> ) } ``` ## Splat / Catch-All Routes A route with a path ending in `$` (bare dollar sign) captures everything after it. The value is available under the `_splat` key. ```tsx // src/routes/files.$.tsx import { createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/files/$')({ component: FileViewer, }) function FileViewer() { const { _splat } = Route.useParams() // URL: /files/documents/report.pdf → _splat = "documents/report.pdf" return <div>File path: {_splat}</div> } ``` ## Optional Params Optional params use `{-$paramName}` syntax. The segment may or may not be present. When absent, the value is `undefined`. ```tsx // src/routes/posts.{-$category}.tsx import { createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/posts/{-$category}')({ component: PostsComponent, }) function PostsComponent() { const { category } = Route.useParams() // URL: /posts → category is undefined // URL: /posts/tech → category is "tech" return <div>{category ? `Posts in ${category}` : 'All Posts'}</div> } ``` Multiple optional params: ```tsx // Matches: /posts, /posts/tech, /posts/tech/hello-world export const Route = createFileRoute('/posts/{-$category}/{-$slug}')({ component: PostComponent, }) ``` ### i18n with Optional Locale ```tsx // src/routes/{-$locale}/about.tsx import { createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/{-$locale}/about')({ component: AboutComponent, }) function AboutComponent() { const { locale } = Route.useParams() const currentLocale = locale || 'en' return <h1>{currentLocale === 'fr' ? 'À Propos' : 'About Us'}</h1> } // Matches: /about, /en/about, /fr/about ``` ## Prefix and Suffix Patterns Curly braces `{}` around `$paramName` allow text before or after the dynamic part within a single segment. ### Prefix ```tsx // src/routes/posts/post-{$postId}.tsx import { createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/posts/post-{$postId}')({ component: PostComponent, }) function PostComponent() { const { postId } = Route.useParams() // URL: /posts/post-123 → postId = "123" return <div>Post ID: {postId}</div> } ``` ### Suffix ```tsx // src/routes/files/{$fileName}[.]txt.tsx import { createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/files/{$fileName}.txt')({ component: FileComponent, }) function FileComponent() { const { fileName } = Route.useParams() // URL: /files/readme.txt → fileName = "readme" return <div>File: {fileName}.txt</div> } ``` ### Combined Prefix + Suffix ```tsx // URL: /users/user-456.json → userId = "456" export const Route = createFileRoute('/users/user-{$userId}.json')({ component: UserComponent, }) function UserComponent() { const { userId } = Route.useParams() return <div>User: {userId}</div> } ``` ## Navigating with Path Params ### Object Form ```tsx import { Link } from '@tanstack/react-router' function PostLink({ postId }: { postId: string }) { return ( <Link to="/posts/$postId" params={{ postId }}> View Post </Link> ) } ``` ### Function Form (Preserves Other Params) ```tsx function PostLink({ postId }: { postId: string }) { return ( <Link to="/posts/$postId" params={(prev) => ({ ...prev, postId })}> View Post </Link> ) } ``` ### Programmatic Navigation ```tsx import { useNavigate } from '@tanstack/react-router' function GoToPost({ postId }: { postId: string }) { const navigate = useNavigate() return ( <button onClick={() => { navigate({ to: '/posts/$postId', params: { postId } }) }} > Go to Post </button> ) } ``` ### Navigating with Optional Params ```tsx // Include the optional param <Link to="/posts/{-$category}" params={{ category: 'tech' }}> Tech Posts </Link> // Omit the optional param (renders /posts) <Link to="/posts/{-$category}" params={{ category: undefined }}> All Posts </Link> ``` ## Reading Params Outside Route Components ### `useParams` with `from` ```tsx import { useParams } from '@tanstack/react-router' function PostHeader() { const { postId } = useParams({ from: '/posts/$postId' }) return <h2>Post {postId}</h2> } ``` ### `useParams` with `strict: false` ```tsx function GenericBreadcrumb() { const params = useParams({ strict: false }) // params is a union of all possible route params return <span>{params.postId ?? 'Home'}</span> } ``` ## Params in Loaders and `beforeLoad` ```tsx export const Route = createFileRoute('/posts/$postId')({ beforeLoad: async ({ params }) => { // params.postId available here const canView = await checkPermission(params.postId) if (!canView) throw redirect({ to: '/unauthorized' }) }, loader: async ({ params }) => { return fetchPost(params.postId) }, }) ``` ## Allowed Characters By default, params are encoded with `encodeURIComponent`. Allow extra characters via router config: ```tsx import { createRouter } from '@tanstack/react-router' const router = createRouter({ routeTree, pathParamsAllowedCharacters: ['@', '+'], }) ``` Allowed characters: `;`, `:`, `@`, `&`, `=`, `+`, `$`, `,`. ## Common Mistakes ### 1. CRITICAL (cross-skill): Interpolating path params into `to` string ```tsx // WRONG — breaks type safety and param encoding <Link to={`/posts/${postId}`}>Post</Link> // CORRECT — use params prop <Link to="/posts/$postId" params={{ postId }}>Post</Link> ``` ### 2. MEDIUM: Using `*` for splat routes instead of `$` TanStack Router uses `$` for splat routes. The captured value is under `_splat`, not `*`. ```tsx // WRONG (React Router / other frameworks) // <Route path="/files/*" /> // CORRECT (TanStack Router) // File: src/routes/files.$.tsx export const Route = createFileRoute('/files/$')({ component: () => { const { _splat } = Route.useParams() return <div>{_splat}</div> }, }) ``` > Note: `*` works in v1 for backwards compatibility but will be removed in v2. Always use `_splat`. ### 3. MEDIUM: Using curly braces for basic dynamic segments Curly braces are ONLY for prefix/suffix patterns and optional params. Basic dynamic segments use bare `$`. ```tsx // WRONG — braces not needed for basic params createFileRoute('/posts/{$postId}') // CORRECT — bare $ for basic dynamic segments createFileRoute('/posts/$postId') // CORRECT — braces for prefix pattern createFileRoute('/posts/post-{$postId}') // CORRECT — braces for optional param createFileRoute('/posts/{-$category}') ``` ### 4. Params are always strings Path params are always parsed as strings. If you need a number, parse in the loader or component: ```tsx export const Route = createFileRoute('/posts/$postId')({ loader: async ({ params }) => { const id = parseInt(params.postId, 10) if (isNaN(id)) throw notFound() return fetchPost(id) }, }) ``` You can also use `params.parse` and `params.stringify` on the route for bidirectional transformation: ```tsx export const Route = createFileRoute('/posts/$postId')({ params: { parse: (raw) => ({ postId: parseInt(raw.postId, 10) }), stringify: (parsed) => ({ postId: String(parsed.postId) }), }, loader: async ({ params }) => { // params.postId is now number return fetchPost(params.postId) }, }) ```
GitHub에서 보기