Created
July 29, 2025 20:22
-
-
Save lucianobarauna/8d759e6c05eb1d2d9c8dca5abd450015 to your computer and use it in GitHub Desktop.
Provider para queryStrings - Feito para next a princípio
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use client'; | |
import { useRouter, useSearchParams } from 'next/navigation'; | |
import { | |
createContext, | |
ReactNode, | |
useCallback, | |
useContext, | |
useEffect, | |
useLayoutEffect, | |
useState, | |
} from 'react'; | |
interface IQueryParamsState<TApi, TUi> { | |
api: TApi; | |
ui: TUi; | |
} | |
interface IQueryParamsContext<TApi, TUi> { | |
rawParams: IQueryParamsState<TApi, TUi>; | |
setRawParams: React.Dispatch< | |
React.SetStateAction<IQueryParamsState<TApi, TUi>> | |
>; | |
} | |
const QueryParamsContext = createContext< | |
IQueryParamsContext<any, any> | undefined | |
>(undefined); | |
const UI_PREFIX = 'ui_'; | |
export const QueryParamsProvider = < | |
TApi extends Record<string, any>, | |
TUi extends Record<string, any>, | |
>({ | |
children, | |
}: { | |
children: ReactNode; | |
}) => { | |
const searchParams = useSearchParams(); | |
const router = useRouter(); | |
const getInitialParams = () => { | |
const entries = Object.fromEntries(searchParams.entries()); | |
const api: Partial<TApi> = {}; | |
const ui: Partial<TUi> = {}; | |
for (const [key, value] of Object.entries(entries)) { | |
if (key.startsWith(UI_PREFIX)) { | |
//const cleanKey = key.slice(UI_PREFIX.length); | |
ui[key as keyof TUi] = value as TUi[keyof TUi]; | |
} else { | |
api[key as keyof TApi] = value as TApi[keyof TApi]; | |
} | |
} | |
return { | |
api: api as TApi, | |
ui: ui as TUi, | |
}; | |
}; | |
const [rawParams, setRawParams] = useState<IQueryParamsState<TApi, TUi>>({ | |
api: {} as TApi, | |
ui: {} as TUi, | |
}); | |
useLayoutEffect(() => { | |
const initial = getInitialParams(); | |
setRawParams(initial); | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
}, [searchParams]); | |
useEffect(() => { | |
const query = new URLSearchParams(); | |
Object.entries(rawParams.api).forEach(([key, value]) => { | |
if (value != null && value !== '') { | |
query.set(key, value); | |
} | |
}); | |
Object.entries(rawParams.ui).forEach(([key, value]) => { | |
if (value != null && value !== '') { | |
query.set(`${key}`, value); | |
} | |
}); | |
router.replace(`?${query.toString()}`); | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
}, [rawParams]); | |
return ( | |
<QueryParamsContext.Provider value={{ rawParams, setRawParams }}> | |
{children} | |
</QueryParamsContext.Provider> | |
); | |
}; | |
export function useQueryParams< | |
TApi extends Record<string, any>, | |
TUi extends Record<string, any>, | |
>() { | |
const context = useContext( | |
QueryParamsContext as React.Context< | |
IQueryParamsContext<TApi, TUi> | undefined | |
> | |
); | |
if (!context) { | |
throw new Error('useQueryParams must be used within a QueryParamsProvider'); | |
} | |
const { rawParams, setRawParams } = context; | |
const updateParams = useCallback( | |
( | |
next: Partial< | |
{ [K in keyof TApi]: TApi[K] } & { | |
[K in keyof TUi]: TUi[K]; | |
} | |
> | |
) => { | |
setRawParams((prev) => { | |
const updatedApi = { ...prev.api }; | |
const updatedUi = { ...prev.ui }; | |
Object.entries(next).forEach(([key, value]) => { | |
if (key.startsWith(UI_PREFIX)) { | |
//const cleanKey = key.slice(UI_PREFIX.length); | |
updatedUi[key as keyof TUi] = value as TUi[keyof TUi]; | |
} else { | |
updatedApi[key as keyof TApi] = value as TApi[keyof TApi]; | |
} | |
}); | |
return { | |
api: updatedApi, | |
ui: updatedUi, | |
}; | |
}); | |
}, | |
[setRawParams] | |
); | |
const setParams = useCallback( | |
( | |
updater: ( | |
prev: IQueryParamsState<TApi, TUi> | |
) => IQueryParamsState<TApi, TUi> | |
) => { | |
setRawParams((prev) => updater(prev)); | |
}, | |
[setRawParams] | |
); | |
return { | |
params: rawParams, | |
updateParams, | |
setParams, | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment