You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
76 lines
2.2 KiB
TypeScript
76 lines
2.2 KiB
TypeScript
import { StateUpdater, useEffect, useState } from 'preact/hooks'
|
|
|
|
import { createContext } from 'preact'
|
|
import { prependBaseUrl } from '../shared/utils'
|
|
|
|
type Metadata = {
|
|
title?: string
|
|
description?: string
|
|
}
|
|
|
|
export const MetadataContext = createContext<Metadata>({})
|
|
|
|
export const ServerContext = createContext<boolean>(false)
|
|
export const ClientContext = createContext<boolean>(false)
|
|
|
|
type RefreshFunction = () => AbortController
|
|
type HeuristicStateUpdater<S> = StateUpdater<S>
|
|
|
|
type ResourceHookFunction = <T>(
|
|
url: string | (() => string),
|
|
initialValue: T,
|
|
onValue?: (value: T) => void
|
|
) => [T, RefreshFunction, HeuristicStateUpdater<T>]
|
|
|
|
export const useResource: ResourceHookFunction = (url, initialValue, onValue) => {
|
|
const [value, setValue] = useState(initialValue)
|
|
|
|
function refresh() {
|
|
const controller = new AbortController()
|
|
const realUrl = typeof url === 'function' ? url() : url
|
|
|
|
fetch(prependBaseUrl(realUrl), { signal: controller.signal })
|
|
.then(res => {
|
|
if (res.ok) {
|
|
return res.json()
|
|
} else {
|
|
return initialValue
|
|
}
|
|
})
|
|
.then(newValue => {
|
|
onValue?.(newValue)
|
|
setValue(newValue)
|
|
})
|
|
|
|
return controller
|
|
}
|
|
|
|
useEffect(() => {
|
|
const controller = refresh()
|
|
return () => {
|
|
controller.abort()
|
|
}
|
|
}, [])
|
|
|
|
return [value, refresh, setValue]
|
|
}
|
|
|
|
type HeuristicListItemUpdater<S> = (index: number, value: S | ((prevValue: S) => S)) => void
|
|
|
|
export const useListResource = <T,>(
|
|
url: string | (() => string)
|
|
): [T[], RefreshFunction, HeuristicListItemUpdater<T>, HeuristicStateUpdater<T[]>] => {
|
|
const [list, refreshList, setListHeuristic] = useResource<T[]>(url, [])
|
|
|
|
const setItemHeuristic: HeuristicListItemUpdater<T> = (index, newValue) => {
|
|
setListHeuristic(list => {
|
|
const newList = [...list]
|
|
// @ts-ignore
|
|
newList[index] = typeof newValue === 'function' ? newValue(list[index]) : newValue
|
|
return newList
|
|
})
|
|
}
|
|
|
|
return [list, refreshList, setItemHeuristic, setListHeuristic]
|
|
}
|