refactor: replace useQueryState with useSuspenseQueryState in ScriptContent and MobileSidebar components; add use-suspense-query-state hook

This commit is contained in:
Bram Suurd
2025-09-29 16:54:51 +02:00
parent 75d26f2de6
commit bfad01fc91
3 changed files with 43 additions and 8 deletions

View File

@@ -1,10 +1,10 @@
"use client"; "use client";
import { Suspense, useEffect, useState } from "react"; import { Suspense, useEffect, useState } from "react";
import { Loader2 } from "lucide-react"; import { Loader2 } from "lucide-react";
import { useQueryState } from "nuqs";
import type { Category, Script } from "@/lib/types"; import type { Category, Script } from "@/lib/types";
import { useSuspenseQueryState } from "@/hooks/use-suspense-query-state";
import { ScriptItem } from "@/app/scripts/_components/script-item"; import { ScriptItem } from "@/app/scripts/_components/script-item";
import { fetchCategories } from "@/lib/data"; import { fetchCategories } from "@/lib/data";
@@ -14,8 +14,8 @@ import Sidebar from "./_components/sidebar";
export const dynamic = "force-static"; export const dynamic = "force-static";
function ScriptContent() { function ScriptContent() {
const [selectedScript, setSelectedScript] = useQueryState("id"); const [selectedScript, setSelectedScript] = useSuspenseQueryState("id");
const [selectedCategory, setSelectedCategory] = useQueryState("category"); const [selectedCategory, setSelectedCategory] = useSuspenseQueryState("category");
const [links, setLinks] = useState<Category[]>([]); const [links, setLinks] = useState<Category[]>([]);
const [item, setItem] = useState<Script>(); const [item, setItem] = useState<Script>();

View File

@@ -1,11 +1,11 @@
"use client"; "use client";
import { useCallback, useEffect, useState } from "react"; import { Suspense, useCallback, useEffect, useState } from "react";
import { useQueryState } from "nuqs";
import { Menu } from "lucide-react"; import { Menu } from "lucide-react";
import type { Category, Script } from "@/lib/types"; import type { Category, Script } from "@/lib/types";
import { useSuspenseQueryState } from "@/hooks/use-suspense-query-state";
import { ScriptItem } from "@/app/scripts/_components/script-item"; import { ScriptItem } from "@/app/scripts/_components/script-item";
import Sidebar from "@/app/scripts/_components/sidebar"; import Sidebar from "@/app/scripts/_components/sidebar";
import { fetchCategories } from "@/lib/data"; import { fetchCategories } from "@/lib/data";
@@ -13,13 +13,13 @@ import { fetchCategories } from "@/lib/data";
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "../ui/sheet"; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "../ui/sheet";
import { Button } from "../ui/button"; import { Button } from "../ui/button";
function MobileSidebar() { function MobileSidebarContent() {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [categories, setCategories] = useState<Category[]>([]); const [categories, setCategories] = useState<Category[]>([]);
const [lastViewedScript, setLastViewedScript] = useState<Script | undefined>(undefined); const [lastViewedScript, setLastViewedScript] = useState<Script | undefined>(undefined);
const [selectedScript, setSelectedScript] = useQueryState("id"); const [selectedScript, setSelectedScript] = useSuspenseQueryState("id");
const [selectedCategory, setSelectedCategory] = useQueryState("category"); const [selectedCategory, setSelectedCategory] = useSuspenseQueryState("category");
const loadCategories = useCallback(async () => { const loadCategories = useCallback(async () => {
setIsLoading(true); setIsLoading(true);
@@ -113,4 +113,12 @@ function MobileSidebar() {
); );
} }
function MobileSidebar() {
return (
<Suspense fallback={null}>
<MobileSidebarContent />
</Suspense>
);
}
export default MobileSidebar; export default MobileSidebar;

View File

@@ -0,0 +1,27 @@
"use client";
import type { SetStateAction } from "react";
import { useSearchParams } from "next/navigation";
import { useTransition } from "react";
import { useQueryState } from "nuqs";
type SuspenseQueryStateSetter<T> = (value: SetStateAction<T | null>) => void;
type SuspenseQueryStateTuple<T> = [T | null, SuspenseQueryStateSetter<T>];
export function useSuspenseQueryState<T extends string>(key: string): SuspenseQueryStateTuple<T> {
const params = useSearchParams();
const [, startTransition] = useTransition();
const [value, setValue] = useQueryState<T | null>(key, { shallow: true, parse: value => value as T | null });
if (!params) {
throw new Error("useSuspenseQueryState must be used within a Next.js app router context.");
}
const setNextValue: SuspenseQueryStateSetter<T> = (nextValue) => {
startTransition(() => {
setValue(nextValue);
});
};
return [value, setNextValue];
}