fix: implement persist to storage in useTableFilter

This commit is contained in:
ValdiANS
2026-04-21 15:57:15 +07:00
parent 3b7c7bb13f
commit 15bddc43e2
+54 -8
View File
@@ -1,4 +1,5 @@
import { useCallback, useMemo, useReducer } from 'react';
import { useCallback, useEffect, useMemo, useReducer } from 'react';
import { useTableFilterStore } from '@/stores/table/table-filter.store';
/** Core filter shape (page + pageSize) extended by your custom fields */
export type TableFilterState<TExtra extends Record<string, unknown>> = {
@@ -30,6 +31,9 @@ export type UseTableFilterOptions<TExtra extends Record<string, unknown>> = {
paramMap?: Partial<Record<keyof TableFilterState<TExtra>, string>>;
/** If true, `toSearchParams`/`toQueryString` will omit values equal to defaults */
omitDefaultsInUrl?: boolean;
persist?: boolean;
storeName?: string;
};
function clampToInt(n: number, min = 1) {
@@ -90,9 +94,37 @@ function shallowEqual<T extends Record<string, unknown>>(
export function useTableFilter<TExtra extends Record<string, unknown>>(
options?: UseTableFilterOptions<TExtra>
) {
const defaults = useMemo(
() => createInitialState<TExtra>(options),
[options]
if (options?.persist && !options?.storeName) {
throw new Error(
'storeName is required if persist is true in useTableFilter!'
);
}
const storeName = options?.storeName ?? '';
const persistedState = useTableFilterStore(
useCallback(
(storeState) =>
storeName
? (storeState.data[storeName] as Partial<TableFilterState<TExtra>>)
: undefined,
[storeName]
)
);
const setTableData = useTableFilterStore(
(storeState) => storeState.setTableData
);
const defaults = useMemo(() => {
return createInitialState<TExtra>(options);
}, [options]);
const initialState = useMemo(
() =>
({
...defaults,
...(persistedState as object),
}) as TableFilterState<TExtra>,
[defaults, persistedState]
);
const [state, dispatch] = useReducer(
@@ -106,15 +138,22 @@ export function useTableFilter<TExtra extends Record<string, unknown>>(
case 'SET_PAGE_SIZE': {
const pageSize = clampToInt(a.pageSize);
const page = a.resetPage ? 1 : s.page;
return { ...s, pageSize, page };
}
case 'SET_FILTERS': {
const page = a.resetPage ? 1 : s.page;
return { ...s, ...a.filters, page };
}
case 'UPDATE_FILTER': {
const page = a.resetPage ? 1 : s.page;
return { ...s, [a.key]: a.value, page } as TableFilterState<TExtra>;
return {
...s,
[a.key]: a.value,
page,
} as TableFilterState<TExtra>;
}
case 'REPLACE_ALL':
return {
@@ -128,12 +167,19 @@ export function useTableFilter<TExtra extends Record<string, unknown>>(
return s;
}
},
defaults
initialState
);
// Notify consumer on change (stable ref)
useEffect(() => {
if (!options?.persist || !storeName) {
return;
}
setTableData(storeName, state);
}, [options?.persist, setTableData, state, storeName]);
const onChange = options?.onChange;
useMemo(() => {
useEffect(() => {
if (onChange) onChange(state);
}, [state, onChange]);