import { useRouter, useSearch } from "@tanstack/react-router";
import { useMemo } from "react";
export type Parser<T> = {
parse: (value: string | null) => T | null;
stringify: (value: T | null) => string | null;
};
export const stringParser: Parser<string> = {
parse: (value) => value ?? null,
stringify: (value) => value ?? null,
};
export const numberParser: Parser<number> = {
parse: (value) => (value ? parseFloat(value) : null),
stringify: (value) => (value !== null ? String(value) : null),
};
export const booleanParser: Parser<boolean> = {
parse: (value) =>
value === "true" ? true : value === "false" ? false : null,
stringify: (value) => (value !== null ? String(value) : null),
};
export const useQueryState = <T>(
key: string,
parser: Parser<T>,
defaultValue: T | null = null
): [T | null, (value: T | null) => void] => {
const router = useRouter();
const searchParams = useSearch({ strict: false });
const value = useMemo(() => {
const paramValue = searchParams[key as keyof typeof searchParams];
return parser.parse(paramValue ? String(paramValue) : null) ?? defaultValue;
}, [searchParams, key, parser, defaultValue]);
const setValue = (newValue: T | null) => {
router.navigate({
search: (prev) => {
return {
...prev,
[key]: parser.stringify(newValue),
};
},
});
};
return [value, setValue];
};
import { useRouter, useSearch } from "@tanstack/react-router";
import { useMemo } from "react";
export type Parser<T> = {
parse: (value: string | null) => T | null;
stringify: (value: T | null) => string | null;
};
export const stringParser: Parser<string> = {
parse: (value) => value ?? null,
stringify: (value) => value ?? null,
};
export const numberParser: Parser<number> = {
parse: (value) => (value ? parseFloat(value) : null),
stringify: (value) => (value !== null ? String(value) : null),
};
export const booleanParser: Parser<boolean> = {
parse: (value) =>
value === "true" ? true : value === "false" ? false : null,
stringify: (value) => (value !== null ? String(value) : null),
};
export const useQueryState = <T>(
key: string,
parser: Parser<T>,
defaultValue: T | null = null
): [T | null, (value: T | null) => void] => {
const router = useRouter();
const searchParams = useSearch({ strict: false });
const value = useMemo(() => {
const paramValue = searchParams[key as keyof typeof searchParams];
return parser.parse(paramValue ? String(paramValue) : null) ?? defaultValue;
}, [searchParams, key, parser, defaultValue]);
const setValue = (newValue: T | null) => {
router.navigate({
search: (prev) => {
return {
...prev,
[key]: parser.stringify(newValue),
};
},
});
};
return [value, setValue];
};