Skip to content

3. tabの状態をqueryに持たせる

tabの状態をqueryに持たせる

さぁこれから実際にHands-onを始めて行きましょう。

まずは、http://localhost:3000/にアクセスしてみてください。 下記のようなページが表示されるはずです。

最初のページ

このページには、Sign-upLogin の二つのタブがあります。

それぞれをクリックすると、タブが切り替わります。

このタブの状態をURLに持たせることで、ブラウザのリロードやリンクをクリックした際にもタブの状態を保持することができます。

現状の確認

現在は、タブの状態を保持していないため、リロードやリンクをクリックした際にタブの状態がリセットされてしまいます。 試しに、タブをLoginに切り替えてからリロードしてみてください。 Sign-upに戻ってしまいます。

修正する

まずは、Page の query を取得するために、Props を受け取るように修正します。

apps/workspace/app/page.tsx
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
export default function Home() {
export default function Home(props: {
searchParams: Record<string, string | string[] | undefined>;
}) {

その次に、tabの値を取得します。

apps/workspace/app/page.tsx
export default function Home(props: {
searchParams: Record<string, string | string[] | undefined>;
}) {
const tabValue = props.searchParams.tab === "login" ? "login" : "sign-up";
return (

次に、TabsコンポーネントにtabValueを渡します。

apps/workspace/app/page.tsx
<Tabs defaultValue="sign-up" className="w-[400px]">
<Tabs value={tabValue} className="w-[400px]">

そして、TabsTriggerコンポーネントにonClickを追加して、タブの更新時にqueryを更新するようにします。

apps/workspace/components/ui/tabs.tsx
import { cn } from "@/lib/utils";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useCallback } from "react";
const Tabs = TabsPrimitive.Root;
...
const TabsTrigger = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
>(({ className, value, ...props }, ref) => {
>(({ className, value, onClick, ...props }, ref) => {
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
const createQueryString = useCallback(
(name: string, value: string) => {
const params = new URLSearchParams(searchParams.toString());
params.set(name, value);
return params.toString();
},
[searchParams],
);
const handleClick = useCallback(
(event: React.MouseEvent<HTMLButtonElement>) => {
event.preventDefault();
const query = createQueryString("tab", value);
router.push(`${pathname}?${query}`);
onClick?.(event);
},
[createQueryString, pathname, value, router, onClick],
);
return (
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
className,
)}
value={value}
onClick={handleClick}
{...props}
/>
);
});
...

これで、タブの状態をURLに持たせることができました。 改めて、タブをLoginに切り替えてからリロードしてみてください。 Loginのままになっているはずです。

まとめ

今回は、タブの状態をURLに持たせる方法を学びました。

これで、ブラウザのリロードやリンクをクリックした際にもタブの状態を保持することができるようになりました。

これを応用することで、モーダルを開いた状態のリンクを共有するなど、様々な用途に活用することができます。