Created
August 12, 2020 18:28
-
-
Save ka7eh/9c985209de1d52eceda8be58f87354fa to your computer and use it in GitHub Desktop.
A custom React hook that returns an object containing an element's position and size attributes. The object gets updated on window resize.
This file contains hidden or 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
| type ElementRect = { | |
| width: number | null; | |
| height: number | null; | |
| top: number | null; | |
| right: number | null; | |
| bottom: number | null; | |
| left: number | null; | |
| marginTop: number | null; | |
| marginRight: number | null; | |
| marginBottom: number | null; | |
| marginLeft: number | null; | |
| paddingTop: number | null; | |
| paddingRight: number | null; | |
| paddingBottom: number | null; | |
| paddingLeft: number | null; | |
| } | |
| /** | |
| * A custom hook that returns an array of a `red` and `rect` objects. | |
| * `ref` can be assigned to an element via its `ref` attribute and then the hook handles changes in the element position | |
| * and size and returns those relevant attributes such as top, left, width, and height in `rect`. | |
| * This is handles via `handleResize` event listener. This event listener is added on component mount | |
| * and removed on unmount. | |
| * | |
| * @returns {[{current: (HTMLElement|null)}, ElementRect]} | |
| */ | |
| export const useElementRect = (): [{ current: HTMLElement | null }, ElementRect] => { | |
| const INITIAL_RECT = { | |
| width: null, | |
| height: null, | |
| top: null, | |
| right: null, | |
| bottom: null, | |
| left: null, | |
| marginTop: null, | |
| marginRight: null, | |
| marginBottom: null, | |
| marginLeft: null, | |
| paddingTop: null, | |
| paddingRight: null, | |
| paddingBottom: null, | |
| paddingLeft: null | |
| }; | |
| const ref: { current: HTMLElement | null } = useRef(null); | |
| const [rect, setRect] = useState(INITIAL_RECT); | |
| const handleResize = () => { | |
| let updatedRect = INITIAL_RECT; | |
| if (ref.current) { | |
| const { | |
| width, | |
| height, | |
| top, | |
| bottom, | |
| right, | |
| left | |
| } = ref.current.getBoundingClientRect(); | |
| const refStyle = window.getComputedStyle(ref.current); | |
| const paddingTop = parseFloat(refStyle.paddingTop); | |
| const paddingRight = parseFloat(refStyle.paddingRight); | |
| const paddingBottom = parseFloat(refStyle.paddingBottom); | |
| const paddingLeft = parseFloat(refStyle.paddingLeft); | |
| const marginTop = parseFloat(refStyle.marginTop); | |
| const marginRight = parseFloat(refStyle.marginRight); | |
| const marginBottom = parseFloat(refStyle.marginBottom); | |
| const marginLeft = parseFloat(refStyle.marginLeft); | |
| updatedRect = { | |
| width: width - paddingLeft - paddingRight - marginLeft - marginRight, | |
| height: height - paddingTop - paddingBottom - marginTop - marginBottom, | |
| top, | |
| right, | |
| bottom, | |
| left, | |
| marginTop, | |
| marginRight, | |
| marginBottom, | |
| marginLeft, | |
| paddingTop, | |
| paddingRight, | |
| paddingBottom, | |
| paddingLeft | |
| }; | |
| } | |
| setRect(updatedRect); | |
| }; | |
| useEffect(() => { | |
| handleResize(); | |
| window.addEventListener('resize', handleResize); | |
| return () => window.removeEventListener('resize', handleResize); | |
| }, []); | |
| return [ref, rect]; | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment