Refactor generator to prevent duplicate reloading

This commit is contained in:
Misode
2022-05-08 16:24:39 +02:00
parent 2772d967e0
commit a432479672
13 changed files with 78 additions and 75 deletions

View File

@@ -1,13 +1,14 @@
import type { Inputs } from 'preact/hooks'
import { useEffect } from 'preact/hooks'
import type { AsyncState } from './useAsyncFn'
import type { AsyncCancel, AsyncState } from './useAsyncFn'
import { useAsyncFn } from './useAsyncFn'
export function useAsync<T>(
fn: () => Promise<T>,
export function useAsync<R>(
fn: () => Promise<R | typeof AsyncCancel>,
inputs: Inputs = [],
): AsyncState<T> {
const [state, callback] = useAsyncFn<T, () => Promise<T>>(fn, inputs, { loading: true })
initialState: AsyncState<R> = { loading: true },
): AsyncState<R> {
const [state, callback] = useAsyncFn<R, () => Promise<R | typeof AsyncCancel>>(fn, inputs, initialState)
useEffect(() => {
callback()

View File

@@ -20,11 +20,13 @@ export type AsyncState<T> = {
value: T,
}
export function useAsyncFn<R, T extends (...args: any[]) => Promise<R>>(
export const AsyncCancel = Symbol('async-cancel')
export function useAsyncFn<R, T extends (...args: any[]) => Promise<R | typeof AsyncCancel>>(
fn: T,
inputs: Inputs = [],
initialState: AsyncState<R> = { loading: false },
): [AsyncState<R>, (...args: Parameters<T>) => Promise<R | undefined>] {
): [AsyncState<R>, (...args: Parameters<T>) => Promise<R | typeof AsyncCancel | undefined>] {
const [state, setState] = useState<AsyncState<R>>(initialState)
const isMounted = useRef<boolean>(false)
const lastCallId = useRef(0)
@@ -34,7 +36,7 @@ export function useAsyncFn<R, T extends (...args: any[]) => Promise<R>>(
return () => isMounted.current = false
}, [])
const callback = useCallback((...args: Parameters<T>): Promise<R | undefined> => {
const callback = useCallback((...args: Parameters<T>): Promise<R | typeof AsyncCancel | undefined> => {
const callId = ++lastCallId.current
if (!state.loading) {
setState(prev => ({ ...prev, loading: true }))
@@ -42,7 +44,7 @@ export function useAsyncFn<R, T extends (...args: any[]) => Promise<R>>(
return fn(...args).then(
value => {
if (isMounted.current && callId === lastCallId.current) {
if (isMounted.current && callId === lastCallId.current && value !== AsyncCancel) {
setState({ value, loading: false })
}
return value

View File

@@ -25,6 +25,7 @@ export function useSearchParam(param: string): [string | undefined, (value: stri
const changeValue = useCallback((newValue: string | undefined, replace?: boolean) => {
if (newValue !== value) {
setValue(newValue)
const params = new URLSearchParams(location.search)
if (newValue === undefined || newValue.length === 0) {
params.delete(param)