Last active
June 14, 2019 13:32
-
-
Save cahilfoley/10e27040bd885b588805a0b2a943de1d to your computer and use it in GitHub Desktop.
[React Hooks] Random React hooks that I've come across and thought were usefull #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 { useCallback, useLayoutEffect, useState, useRef } from 'react' | |
/** | |
* Returns the bounding client rect of a HTML element, uses the `ResizeObserver` api if available to detect changes to the | |
* size. Falls back to listening for resize events on the window. | |
*/ | |
export function useBoundingRect<T extends HTMLElement>(): [React.Ref<T>, ClientRect | DOMRect] { | |
const ref = useRef<T>() | |
const [rect, setRect] = useState() | |
const recalculator = useCallback(() => { | |
if (ref.current) { | |
setRect(ref.current.getBoundingClientRect()) | |
} | |
}, [ref]) | |
// Handle changing of size | |
useLayoutEffect(() => { | |
const { ResizeObserver } = window | |
if (!ref.current) return | |
recalculator() | |
window.addEventListener('resize', recalculator) | |
let resizeObserver: ResizeObserver | |
if (typeof ResizeObserver === 'function') { | |
resizeObserver = new ResizeObserver(recalculator) | |
resizeObserver.observe(ref.current) | |
} | |
return () => { | |
window.removeEventListener('resize', recalculator) | |
if (resizeObserver) resizeObserver.disconnect() | |
} | |
}, [ref, recalculator]) | |
// Handle document scroll | |
useLayoutEffect(() => { | |
document.addEventListener('scroll', recalculator) | |
return () => document.removeEventListener('scroll', recalculator) | |
}) | |
return [ref, rect] | |
} |
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, useLayoutEffect, useState, useRef } from 'react' | |
// For the implmentation of this see https://gist.github.com/849805a6e0c4e3d71619f278e495f105#file-measurement-ts | |
import { getSize } from '../utils' | |
/** | |
* Returns the height and width of a HTML element, uses the `ResizeObserver` api if available to detect changes to the | |
* size. Falls back to listening for resize events on the window. | |
*/ | |
export function useComponentSize<T extends HTMLElement>(): [ | |
React.Ref<T>, | |
ReturnType<typeof getSize> | |
] { | |
const ref = useRef<T>() | |
const [size, setSize] = useState(getSize(ref.current)) | |
const resizeHandler = useCallback(() => { | |
if (ref.current) { | |
setSize(getSize(ref.current)) | |
} | |
}, [ref]) | |
useLayoutEffect(() => { | |
const { ResizeObserver } = window | |
if (!ref.current) return | |
resizeHandler() | |
if (typeof ResizeObserver === 'function') { | |
const resizeObserver = new ResizeObserver(resizeHandler) | |
resizeObserver.observe(ref.current) | |
return () => resizeObserver.disconnect() | |
} else { | |
window.addEventListener('resize', resizeHandler) | |
return () => window.removeEventListener('resize', resizeHandler) | |
} | |
}, [ref, resizeHandler]) | |
return [ref, size] | |
} |
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' | |
type EventHandler<T extends Event> = (event: T) => any | |
export function useEventListener<T extends keyof DocumentEventMap>( | |
eventName: T, | |
handler: EventHandler<DocumentEventMap[T]>, | |
element: HTMLElement = document.documentElement, | |
) { | |
const savedHandler = useRef<EventHandler<DocumentEventMap[T]>>() | |
// Update a ref to the latest handler whenever it changes | |
useEffect(() => { | |
savedHandler.current = handler | |
}, [handler]) | |
useEffect(() => { | |
// Ensure add event listener is supported | |
if (!(element && element.addEventListener)) return | |
// Use the latest event handler in the listener | |
const eventListener = (event: DocumentEventMap[T]) => | |
savedHandler.current && savedHandler.current(event) | |
// Add listener and cleanup | |
element.addEventListener(eventName, eventListener) | |
return () => element.removeEventListener(eventName, eventListener) | |
}, [eventName, element]) | |
} |
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 { useRef, useState } from 'react' | |
import { useEventListener } from './useEventListener' | |
interface UseMousePositionOptions { | |
/** Throttle the updates to only occur every x ms */ | |
throttle?: number | |
} | |
export function useMousePosition(options: UseMousePositionOptions = {}) { | |
const [position, setPosition] = useState(() => ({ clientX: 0, clientY: 0 })) | |
const lastUpdate = useRef(0) | |
useEventListener('mousemove', ({ clientX, clientY }) => { | |
const now = Date.now() | |
if (options.throttle && now - lastUpdate.current < options.throttle) return | |
setPosition({ clientX, clientY }) | |
lastUpdate.current = now | |
}) | |
return [position] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment