Last active
January 6, 2021 02:42
-
-
Save Twipped/f9dd76cda895b6244b1bcc38b9b3f17e to your computer and use it in GitHub Desktop.
A small collection of useful react hooks
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 { | |
isSameDay, | |
isSameYear, | |
isSameHour, | |
isSameMinute, | |
isSameMonth, | |
isSameSecond, | |
isSameWeek, | |
} from 'date-fns'; | |
import { useState, useEffect, useRef } from 'react'; | |
export const YEARS = isSameYear; | |
export const MONTHS = isSameMonth; | |
export const WEEKS = isSameWeek; | |
export const DAYS = isSameDay; | |
export const HOURS = isSameHour; | |
export const MINUTES = isSameMinute; | |
export const SECONDS = isSameSecond; | |
export default function useClock (...checks) { | |
checks = checks.flat(Infinity).filter((c) => typeof c === 'function'); | |
if (!checks.length) throw new Error('You must provide tick functions to check against.'); | |
const timerID = useRef(null); | |
const [ date, setDate ] = useState(new Date()); | |
function tick () { | |
const now = new Date(); | |
for (const check of checks) { | |
if (!check(now, date)) { | |
setDate(now); | |
return; | |
} | |
} | |
} | |
useEffect(() => { | |
timerID.current = setInterval( () => tick(), 1000 ); | |
return () => { clearInterval(timerID.current); }; | |
}, []); | |
return date; | |
} | |
useClock.YEARS = YEARS; | |
useClock.MONTHS = MONTHS; | |
useClock.WEEKS = WEEKS; | |
useClock.DAYS = DAYS; | |
useClock.HOURS = HOURS; | |
useClock.MINUTES = MINUTES; | |
useClock.SECONDS = SECONDS; |
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 useImmediateUpdateEffect from './useImmediateUpdateEffect'; | |
import { useMemo, useCallback, useState } from 'react'; | |
/** | |
* Creates a state hook populated by a value derived from dependencies. | |
* If the dependencies change, the state will be repopulated based on the new dependencies, IF the results differ. | |
* @param {Function} fn Handler to run at initialization and when a dependency changes | |
* @param {Array<mixed>} deps A dependency array | |
* @param {Function} comparator A function to evaluate if the result of the handler differs from current state | |
*/ | |
const strictEqual = (a, b) => (a === b); | |
export default function useDerivedState (fn, deps, comparator = strictEqual) { | |
if (typeof fn === 'function') { | |
fn = useCallback(fn, deps); | |
} else { | |
const v = fn; | |
fn = useCallback(() => v, [ v ]); | |
} | |
const initial = useMemo(fn, deps); | |
var [ state, writeState ] = useState(initial); | |
useImmediateUpdateEffect(() => { | |
const res = fn(); | |
if (comparator(state, res)) writeState(res); | |
}, deps); | |
return [ state, writeState ]; | |
} |
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 useWillUnmount from './useWillUnmount'; | |
import { useRef, useMemo } from 'react'; | |
/** | |
* An _immediate_ effect that runs an effect callback when its dependency array | |
* changes. This is helpful for updates should must run during render, most | |
* commonly state derived from props; a more ergonomic version of https://reactjs.org/docs/hooks-faq.html#how-do-i-implement-getderivedstatefromprops | |
* | |
* ```ts | |
* function Example({ value }) { | |
* const [intermediaryValue, setValue] = useState(value); | |
* | |
* useImmediateUpdateEffect(() => { | |
* setValue(value) | |
* }, [value]) | |
* ``` | |
*/ | |
export default function useImmediateUpdateEffect (effect, deps) { | |
const firstRef = useRef(true); | |
const tearDown = useRef(); | |
useWillUnmount(() => { | |
if (tearDown.current) tearDown.current(); | |
}); | |
useMemo(() => { | |
if (firstRef.current) { | |
firstRef.current = false; | |
return; | |
} | |
if (tearDown.current) tearDown.current(); | |
tearDown.current = effect(); | |
}, deps); | |
} |
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 { useEffect, useRef } from 'react'; | |
/** | |
* Attach a callback that fires when a component unmounts | |
* | |
* @param fn Handler to run when the component unmounts | |
* @category effects | |
*/ | |
export default function useWillUnmount (fn) { | |
const onUnmount = useRef(fn); | |
onUnmount.current = fn; | |
useEffect(() => () => onUnmount.current(), []); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment