Last active
September 18, 2021 19:12
-
-
Save generalpiston/3dfcd808d0ca0e016653a01e5c7b5c84 to your computer and use it in GitHub Desktop.
Hook for storing, removing, and going to next location in search parameters and provides a default. Automatically clears when going to next location.
This file contains 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
import { useCallback, useMemo } from 'react' | |
interface NextActions { | |
go: () => void | |
setValue: (next?: string) => void | |
clear: () => void | |
status: 'query' | |
} | |
interface DefaultNextActions { | |
go: () => void | |
status: 'default' | |
} | |
interface EmptyNextActions { | |
go: () => void | |
status: 'empty' | |
} | |
type NextValue = string | undefined | |
type NextResponseFull = [NextValue, NextActions] | |
type NextResponseDefault = [NextValue, DefaultNextActions] | |
type NextResponseEmpty = [null, EmptyNextActions] | |
type NextResponse = NextResponseFull | NextResponseDefault | NextResponseEmpty | |
interface NextOptions { | |
nextParam: string | |
history: History | |
location: Location | |
} | |
const DefaultNextOptions = { | |
nextParam: 'next', | |
history: window.history, | |
location: window.location | |
} | |
export function useNextQuery(options: NextOptions = DefaultNextOptions): [NextValue, NextActions] { | |
const { history, location, nextParam } = options | |
const next = useMemo(() => { | |
const { search } = location | |
const urlparams = new URLSearchParams(search) | |
return urlparams.get(nextParam) ?? undefined | |
}, [nextParam, location]) | |
const go = useCallback(() => { | |
if (next) { | |
history.pushState({}, next) | |
} | |
}, [next, history]) | |
const clear = useCallback(() => { | |
const { search } = location | |
const urlparams = new URLSearchParams(search) | |
urlparams.delete(nextParam) | |
const url = `${location.origin}?${urlparams.toString()}` | |
history.pushState({}, url) | |
}, [nextParam, history, location]) | |
const setValue = useCallback( | |
(next) => { | |
const { search } = location | |
const urlparams = new URLSearchParams(search) | |
urlparams.set(nextParam, next) | |
const url = `${location.origin}?${urlparams.toString()}` | |
history.pushState({}, url) | |
}, | |
[nextParam, history, location] | |
) | |
return [next, { go, clear, setValue, status: 'query' }] | |
} | |
export function useNextDefault( | |
defaultNext?: string, | |
options: Pick<NextOptions, 'location' | 'history'> = DefaultNextOptions | |
): [NextValue, DefaultNextActions] { | |
const { history } = options | |
const go = useCallback(() => { | |
if (defaultNext) { | |
history.pushState({}, defaultNext) | |
} | |
}, [defaultNext, history]) | |
return [defaultNext, { go, status: 'default' }] | |
} | |
function useNext(): NextResponseFull | NextResponseEmpty | |
function useNext(defaultNext: string): NextResponse | |
/** | |
* 1. Check search parameters for `next`. | |
* 2. Use provided default. | |
*/ | |
function useNext(defaultNext?: string, options: NextOptions = DefaultNextOptions): NextResponse { | |
const search = useNextQuery(options) | |
const otherwise = useNextDefault(defaultNext, options) | |
if (search[0]) { | |
return search | |
} | |
if (otherwise[0]) { | |
return otherwise | |
} | |
return [null, { status: 'empty', go: () => null }] | |
} | |
export default useNext |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment