@k8ordo/router

いまいる場所を調べる

いま開いているページのリンクに印を付けたり、次のページを読み込んでいることを見せたりするには、ブラウザがいまどのパスにいるかを調べます。このページでは、そのためのフックと関数を紹介します。

このページの内容

いまのパスを読む

usePathnameは、ブラウザがいま開いているパスを返します。末尾のスラッシュは落とした形で返ります。

src/current-path.tsx
import { usePathname } from '@k8ordo/router';

export function CurrentPath() {
  const pathname = usePathname();
  return <p>You are at {pathname}</p>;
}

再描画されるのはパスが変わったときだけで、クエリ文字列が変わっても再描画されません。クエリ文字列を返さないのは、その値を読むのが@k8ordo/stateの役割だからです。@k8ordo/stateでは、コンポーネントが読んでいる値が変わったときだけ再描画されます。

パスはURLでの書き方のままで、デコードはしません。日本語のような文字は、パーセントエンコードされた形で返ります。

usePathnameはルート表ではなくブラウザのURLを読むので、@k8ordo/staticや@k8ordo/serverの下でも同じように使えます。

あるページを開いているか調べる

useMatchは、いまのパスがパターンに合えばそのparamsを、合わなければnullを返します。ナビゲーションのリンクに印を付けるときは、これを使います。

src/products-link.tsx
import { href, useMatch } from '@k8ordo/router';

export function ProductsLink() {
  const isCurrent = useMatch('/products') !== null;

  return (
    <a
      aria-current={isCurrent ? 'page' : undefined}
      href={href('/products')}
    >
      Products
    </a>
  );
}

リンクが選ばれているかどうかは、リンクに渡すpropsではなく、こうして尋ねて決めます。<Link>のようなコンポーネントが無いので、印の付け方も自分で選べます。

あるまとまりの下にいるか調べる

パターンの後ろに/*を付けると、「そのパターンより下のどこか」という意味になります。サイドバーのように、どのまとまりを開いているかを知りたいときに使います。

ts
matchPath('/products/*', '/products/42'); // {}
matchPath('/products/*', '/products'); // null
matchPath('/products/*', '/products', { inclusive: true }); // {}

matchPathは、useMatchと同じ判定を、手元にあるパスに対して行う関数です。上の例では、判定の違いが見えるようにこちらを使っています。

/products/*は、/productsそのものには合いません。まとまりの入口のページでも印を付けたいときは、{ inclusive: true }を渡します。

/*を付けられるのは、ルート表にあるパターンの後ろだけです。Registerを登録していれば、表に無いパターンは型エラーになります。

useMatchはusePathnameの上に作られているので、再描画されるのはパスが変わったときだけです。ルート表も要らないので、フレームワークの下でも使えます。このサイトのヘッダーも、パッケージのランディングとその下のページのどちらでもパッケージ名に印が付くよう、inclusiveを付けて判定しています。

Playground

パターンとパスの照合を試す

このサイトも@k8ordo/routerの上で動いています。最初の値は、このページでusePathnameを呼んで読んだパスです。書き換えると、matchPathの結果がその場で変わります。

usePathname()の値/ja/router/location

呼び出し
matchPath('/:locale/router/*', '/ja/router/location')
結果
{"locale":"ja"}

試してみる

  1. 最初は、パターンが/:locale/router/*で、パスがこのページのパスです。結果は{"locale":"ja"}で、/*が受けた部分はparamsに入りません。
  2. パスを/ja/routerに書き換えると、結果はnullになります。/*は、パターン自身のページには合わないからです。
  3. 「inclusive」をオンにすると、結果が{"locale":"ja"}に戻ります。
  4. パスの末尾に/を足しても、結果は変わりません。比べる前に、末尾のスラッシュを落とすからです。

読み込み中のページを知る

ページを移るとき、URLが先に書き換わり、新しいページは準備ができてから画面に出ます。そのため遅いナビゲーションでは、usePathnameがもう新しいパスを返しているのに、画面には前のページが残っています。

usePendingPathnameは、読み込み中のページのパスを返します。何も読み込んでいないときはnullです。

src/progress.tsx
import { usePendingPathname } from '@k8ordo/router';

export function Progress() {
  const pending = usePendingPathname();
  if (pending === null) return null;

  return <p role="status">Loading {pending}…</p>;
}

値はナビゲーションが始まった時点で入り、新しいページが画面に出たときにnullに戻ります。ナビゲーションが中断されたときや、読み込みに失敗したときもnullに戻ります。

クエリ文字列だけを変える状態の更新は、ページの切り替えではないので値が入りません。ただし、フレームワークのページがクエリ文字列を読んでいて、その場で読み込み直すときは、ほかの読み込みと同じように値が入ります。

ページのparamを読む

<Router>で描くページは、useParamsに自分のパターンを渡してparamを読みます。返る値の型はパターンの文字列から決まり、値はいつも文字列です。

src/pages/product-page.tsx
import { useParams } from '@k8ordo/router';

export function ProductPage() {
  const { id } = useParams('/products/:id');
  return <h1>Product {id}</h1>;
}

渡すパターンは、「このコンポーネントはこのパターンのページとして描かれる」という宣言でもあります。別のパターンのページの中で描かれると、形の違うparamsを返す代わりに、次の例外を投げます。

text
useParams("/products/:id") rendered under "/products"

いくつものページで使い回すコンポーネントなら、useRouteで、いま選ばれているパターンとparamsを型の無い形で受け取れます。

ts
const { pattern, params } = useRoute();
警告

落とし穴

useParamsとuseRouteは、<Router>が持つ照合の結果を読みます。@k8ordo/staticや@k8ordo/serverの下ではブラウザにルート表が無いので、どちらも使えません。ページはparamsをpropsで受け取ります。

k8ordo

Baselineに入った機能を、制限なく使うReactのライブラリ群。

© 2026 k8o — MIT License

組版:Noto Sans JP / M PLUS 2