@saramorillon/hooks
v2.12.4
Published
Some utility hooks
Downloads
7
Readme
Hooks
Some utility hooks.
Table of contents
useTheme
useTheme
returns 'dark' or 'light' according to prefers-color-scheme media query.
It also changes document root color-scheme accordingly.
Example
import { useTheme } from '@saramorillon/hooks'
function MyComponent() {
const theme = useTheme()
return theme === 'dark' ? <Dark /> : <Light />
}
API
useTheme(): Theme
Arguments
None
Returns
Theme
- The theme ("light" or "dark").
useQuery
useQuery
provides an easy way to make any action that triggers a loading, may return some data and may generate an error (typical API call use case).
Example
import { useQuery } from '@saramorillon/hooks'
import { getData } from './service'
function MyComponent() {
const { execute, loading, error, result } = useQuery(getData)
if (loading) return <Spinner />
if (error) return <Error />
return (
<>
<Button onClick={execute}>Load data</Button>
<Table data={result} />
</>
)
}
API
useQuery<T>(queryFn: () => Promise<T>, options?: IQueryOptions<T>): IQueryResult<T>
Arguments
queryFn: () => Promise<T>
- The function to run. :warning: Must be memoized to avoid potential infinite loops.
options?: IQueryOptions<T>
- An object containing:
autoRun?: boolean
- indicates weither of not the query should be run automatically on component mountdefaultValue?: T
- the default value returned by the hook
Returns
An object containing:
execute: () => Promise<void>
- the function to execute the actionloading: boolean
- indicates weither the action is currently pending or noterror?: unknown
- the error potentially generated by the actionresult: T
- the value returned by the action
useFetch
:warning: Deprecated, use useQuery
instead.
useFetch
provides an easy way to make any action that triggers a loading, returns some data and may generate an error (typical API call use case).
It also provides a replay function to replay the action and a replace function to replace the data.
Example
import { useFetch } from '@saramorillon/hooks'
import { getData } from './service'
function MyComponent() {
const [data, status, refresh] = useFetch(getData, null)
if (status.loading) return <Spinner />
if (status.error) return <Error />
return (
<>
<Button onClick={refresh} />
<Table data={data} />
</>
)
}
API
useFetch<T>(fetchFn: () => Promise<T>, defaultValue: T, autoFetch: boolean): [T, IFetchedStatus, () => void, React.Dispatch<React.SetStateAction<T>>]
Arguments
fetchFn: () => Promise<T>
- The action to run. :warning: Must be memoized to avoid potential infinite loops.
defaultValue: T
- The default value to return.
autoFetch: boolean
- Weither the fetch function should be run on mount or not. Default is true
.
Returns
An array containing:
T
- the value returned by the actionIFetchedStatus
- an object containingloading: boolean
- indicates weither the action is currently pending or noterror: unknown
- the error potentially generated by the action
() => void
- a replay functionReact.Dispatch<React.SetStateAction<T>>
- a replace function
usePagination
usePagination
provides an easy way to generate a full pagination system.
Example
import { usePagination } from '@saramorillon/hooks'
import { getData } from './service'
const limit = 10
function MyComponent() {
const { page, maxPages, setMaxPages, first, previous, next, last, canPrevious, canNext } = usePagination()
const fetch = useCallback(() => getData(page, limit), [page])
const [{ data, total }] = useFetch(fetch, { data: [], total: 0 })
useEffect(() => {
setMaxPages(Math.ceil(total / limit))
}, [setMaxPages, total])
}
return (
<div>
<button disabled={!canPrevious} onClick={first}>
First page
</button>
<button disabled={!canPrevious} onClick={previous}>
Previous page
</button>
<span>
Page {page} of {maxPages}
</span>
<button disabled={!canNext} onClick={next}>
Next page
</button>
<button disabled={!canNext} onClick={last}>
Last page
</button>
</div>
)
API
usePagination(maxPage: number, initialValue = 1): IPagination
Arguments
maxPage: number
- The maximum page
initialValue?: number
- The initial page (default 1).
Returns
An object containing:
page: number
- the current pagegoTo: React.Dispatch<React.SetStateAction<number>>
- a function to go to a specific pagefirst: () => void
- a function to go to the first pageprevious: () => void
- a function to go to the previous pagenext: () => void
- a function to go to the next pagelast: () => void
- a function to go to the last pagecanPrevious: boolean
- indicates weither the navigation to the previous page is possiblecanNext: boolean
- indicates weither the navigation to the next page is possible
useForm
useForm
provides helpers to handle forms.
Example
import { useForm } from '@saramorillon/hooks'
type Data {
name: string
}
function MyComponent({ data }: { data: Data }) {
const save = useCallback((values: Data) => {
console.log(values)
}, [])
const { values, submit, onChange, reset } = useForm(save, data)
return (
<form onSubmit={submit} onReset={reset}>
<input value={values.name} onChange={(e) => onChange('name', e.target.value)} />
<button type='submit'>Submit</button>
<button type='reset'>Reset</button>
</form>
)
}
API
useForm<T>(props: IFormProps<T>): IForm<T>
Arguments
save: (values: T) => void
- The save action. :warning: Must be memoized to avoid potential infinite loops.
initialValues: T
- The initial values.
Returns
An object containing:
values: T
- the form valuesonChange: <K extends keyof T>(name: K, value: T[K]) => void
- a function to change the values of the formsubmit: (e: FormEvent) => void
- a function for submitting a formreset: () => void
- a function to reset the form to its initial valuesloading: boolean
- indicates when the form is being submittederror?: unknown
- contains a potential error thrown by the save function
useCopy
useCopy
provides helpers to handle clipboard copy.
Example
import { useCopy } from '@saramorillon/hooks'
function MyComponent() {
const [authorized, status, copy] = useCopy()
if (status.loading) return <Spinner />
if (status.error) return <Error />
return (
<button onClick={() => copy('Something')} disabled={!authorized}>
Copy
</button>
)
}
API
useCopy(): [boolean, ICopyStatus, () => void]
Arguments
None
Returns
An array containing:
authorized: boolean
- indicates weither the user authorized clipboard actions on their browerICopyStatus
- an object containingloading: boolean
- indicates weither the copy is currently pending or noterror: unknown
- the error potentially generated by the copy
(data: string) => void
- the copy function
useDrag/useDrop
useDrag
provides helpers to help dragging elements.
Example
import { useDrag, useDrop } from '@saramorillon/hooks'
function MyList() {
const [isDragged, events] = useDrag()
const onDrop = useCallback((source: string, target: string) => {
console.log(`Dragged ${source} on ${target}`)
}, [])
return (
<ul>
<MyListSlot item="Item1" onDrop={onDrop} />
<MyListSlot item="Item2" onDrop={onDrop} />
<MyListSlot item="Item3" onDrop={onDrop} />
</ul>
)
}
function MyListSlot({ item, onDrop }: { item: string; onDrop: (source: string, target: string) => void }) {
const onMove = useCallback((source: string) => onDrop(source, item), [item])
const [isOver, events] = useDrop(onMove)
return (
<div {...events} style={{ backgroundColor: isOver ? 'yellow' : 'transparent' }}>
<MyListItem item={item} />
</div>
)
}
function MyListItem({ item }: { item: string }) {
const [isDragged, events] = useDrag(item)
return (
<div draggable {...events} style={{ color: isDragged ? 'red' : 'blue' }}>
{item}
</div>
)
}
API
useDrag(source: string): [boolean, IDragEvents]
useDrop(onDrop: (source: string) => void): [boolean, IDropEvents]
Arguments
source: string
- The source element. Don't forget to memoize stringified JSON objects.
onDrop: (source: string) => void
- The drop action.
Returns
An array containing:
isDragged: boolean
- indicates weither the item is currently draggedIDragEvents
- an object containing events to attach to the draggable item
An array containing:
isOver: boolean
- indicates weither a dragged item is currently over the targetIDropEvents
- an object containing events to attach to the target
useDialog
useDialog
provides helpers to show and hide native HTML dialogs.
Example
import { useDialog } from '@saramorillon/hooks'
function MyComponent() {
const { ref, visible, show, hide } = useDialog()
return (
<>
<button onClick={show}>Show dialog</button>
<dialog ref={ref} onClick={hide}>
{visible && (
<div onClick={(e) => e.stopPropagation()}>
<button onClick={hide}>Hide dialog</button>
</div>
)}
</dialog>
</>
)
}
API
useDialog(): IDialog
Arguments
None
Returns
An object containing:
ref: RefObject<HTMLDialogElement>
- the dialog refvisible: boolean
- indicates weither the dialog is visible or notshow: () => void
- a function to show the dialoghide: () => void
- a function to hide the dialog
Contribute
Any PR is welcomed! Please be sure to meet following requirements when posting a PR:
- Unit tests pass and code coverage is over 90%
- Code conventions have been respected (
yarn lint
can help) - Code is properly formatted (
yarn format
can help)