[Observer API ํํค์น๊ธฐ] 3. ResizeObserver
- 1. ResizeObserver
- 1.1. options
- 1.1.1. ๋ฐ์ค ์ข ๋ฅ (box)
- 1.2. callback
- 1.2.1. ResizeObserverEntry
- 1.2.1.1. ์ ์ฒด ์์ญ์ ํฌ๊ธฐ ์ ๋ณด (borderBoxSize)
- 1.2.1.2. ์์ ์ปจํ ์ธ ์์ญ์ ํฌ๊ธฐ ์ ๋ณด (contentBoxSize)
- 1.2.1.3. ๊ธฐ๊ธฐ ํฝ์ ๊ธฐ์ค ์ปจํ ์ธ ์์ญ์ ํฌ๊ธฐ ์ ๋ณด (devicePixelContentBoxSize)
- 1.2.1.4. ์์์ ํฌ๊ธฐ ์ ๋ณด (contentRect)
- 1.2.1.5. ์ด๋ฒคํธ ๋์ (target)
- 1.2.2. observer
- 2. React์์ ์ปค์คํ ํ ์ผ๋ก ๊ฐํธํ๊ฒ ์ฌ์ฉํ๊ธฐ
- 2.1. ์ ์ฒด ์ฝ๋
- 2.2. CodeSandbox๋ฅผ ํตํ ์์
- 3. ๋ง์น๋ฉฐ
ResizeObserver๋ ์์์ ํฌ๊ธฐ ๋ณํ๋ฅผ ๊ฐ์งํ๋ ์ต์ ๋ฒ๋ค. ์์์ width, height๊ฐ ๋ณํ ๊ฒฝ์ฐ, ์ด๋ฅผ ๊ฐ์งํ์ฌ ์ํ๋ ๋์์ ์ํํ ์ ์๋ค.
TYPESCRIPT1 2 3const ro = new ResizeObserver(callback); ro.observe(tag, options);
์ด์ ์ฅ์ IntersectionObserver์ ๋ค๋ฅด๊ฒ ์ต์
์ API์์ ํ ๋นํ์ง ์๋๋ค. observe ๋ฉ์๋๋ฅผ ํตํด ์์๋ฅผ ๋ฑ๋กํ ๋, options๋ฅผ ๊ฐ์ด ์ง์ ํ ์ ์๋ค.
์์ ๋ฑ๋ก ์ options๋ฅผ ์ ๋ฌํ์ฌ ์ธ๋ถ ์ต์
์ ์กฐ์ ํ ์ ์๋ค. ResizeObserverOptions ํ์
์ ๊ฐ์ง๋ค.
์์์ ์ข ๋ฅ๋ฅผ ์ง์ ํ๋ค.
content-box- CSS์ ์ ์๋ ์ปจํ ์ธ ์์ญ์ ํฌ๊ธฐborder-box- CSS์ ์ ์๋ ๋ฐ์ค ์ ์ฒด ์์ญ์ ํฌ๊ธฐ (margin,padding,borderํฌํจ)device-pixel-content-box- ๊ธฐ๊ธฐ์ ํฝ์ ๋จ์ ๊ธฐ์ค์ผ๋ก ์ ์๋ ์ปจํ ์ธ ์์ญ์ ํฌ๊ธฐ
ResizeObserver์ ์ฝ๋ฐฑ ๋ฉ์๋๋ ์์์ ํฌ๊ธฐ๊ฐ ๋ณํ ๊ฒฝ์ฐ ๋์ํ๋ ์ด๋ฒคํธ ๋ฉ์๋๋ค.
ResizeObserverCallback ํ์
์ผ๋ก ์ ์ธ๋์ด ์์ผ๋ฉฐ, ์ด๋ฅผ ์ฝ๋๋ก ํ๊ธฐํ๋ฉด ์๋์ ๊ฐ๋ค.
TYPESCRIPT1const ro = new ResizeObserver((entries, observer) => {});
entries๋ ResizeObserverEntry[] ํ์
์ ๊ฐ๋๋ค. ResizeObserverEntry์ ๋ฑ๋ก๋ ์์์ ์ด๋ฒคํธ ์ ๋ณด๋ฅผ ๋ฐฐ์ด ํํ๋ก ๋ฐํํ๋ค.
ResizeObserverEntry์ ์ฌ๋ฌ DOM์ ๋ฑ๋กํ์ฌ, ์ฌ๋ฌ ๊ฐ์ฒด์ ์ต์ ๋ฒ๋ฅผ ์ ์ฉํ ์ ์๋ค.
๊ธฐ๋ณธ ๋ฐ์ค
๊ฐ ์์์ ์๋ฏธ๋ ์ ๋ฐ์ค๋ฅผ ๊ธฐ์ค์ผ๋ก ์ค๋ช ํ๋ค.
border-box
CSS์์ ์ปจํ ์ธ ์ ํฌ๊ธฐ๋ฅผ ๊ตฌ์ฑํ๋ ์์๋ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์๋ค.
๊ฐ๊ฐ border, padding์ผ๋ก ๋ ์ด์์์ด ๊ตฌ์ฑ๋๋ฉฐ, ๋ด๋ถ์ ์ปจํ
์ธ ์ ๋ฐ๋ผ ํฌ๊ธฐ๊ฐ ์ ํด์ง๋ค.
borderBoxSize๋ ์ด ๋ชจ๋ ์์๋ฅผ ์์ฐ๋ฅด๋ ๋ฐ์ค์ ํฌ๊ธฐ๋ฅผ ์ ๊ณตํ๋ค. ๋ฐฐ์ด๋ก ์ด๋ฃจ์ด์ ธ ์์ผ๋ฉฐ, ๊ฐ ์์ดํ
์ blockSize, inlineSize๋ฅผ ๊ฐ์ง๋ค.
blockSize- ๋์ด (height)inlineSize- ๋๋น (width)
content-box
CSS์์ ๋ฐ์ค ๋ ์ด์์์ ๊ตฌ์ฑํ๋ border, padding์ ์ ์ธํ ์์ ์ปจํ
์ธ ์ ํฌ๊ธฐ ์ ๋ณด๋ฅผ ๋ฐํํ๋ค.
borderBoxSize์ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ฐฐ์ด๋ก ์ด๋ฃจ์ด์ ธ ์์ผ๋ฉฐ, ๊ฐ ์์ดํ
์ ์ ๋ณด ์ญ์ ๋์ผํ๋ค.
blockSize- ๋์ด (height)inlineSize- ๋๋น (width)
๊ธฐ๊ธฐ ํฝ์ ๊ธฐ์ค์ ์ปจํ ์ธ ์์ญ ํฌ๊ธฐ ์ ๋ณด๋ฅผ ๋ฐํํ๋ค.
borderBoxSize์ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ฐฐ์ด๋ก ์ด๋ฃจ์ด์ ธ ์์ผ๋ฉฐ, ๊ฐ ์์ดํ
์ ์ ๋ณด ์ญ์ ๋์ผํ๋ค.
blockSize- ๋์ด (height)inlineSize- ๋๋น (width)
contentRect
์์๋ค์ ๋ค์ํ ํฌ๊ธฐ ์ ๋ณด๋ฅผ ๋ฐํํ๋ ๊ฐ์ฒด๋ก, ๋ค๋ฅธ ๊ฐ์ฒด์์ ์ ๊ณตํ๋ ์ ๋ณด๊ฐ ์ผ๋ถ ์ค๋ณต๋์ด ์๋ค.
ํด๋น ๊ฐ์ฒด๋ ๋ ๊ฑฐ์ ์์ฑ์ผ๋ก, ํธํ์ฑ ์ ์ง๋ก ์ธํด ์ง์๋๊ณ ์์ผ๋ฉฐ, ์ธ์ ๊ฐ ์ง์ ์ข ๋ฃ๋ ๊ฐ๋ฅ์ฑ์ด ์๋ค.
width- ์์ ์ปจํ ์ธ ์์ญ์ ๋๋น (contentBoxSize์ ๋์ผ)height- ์์ ์ปจํ ์ธ ์์ญ์ ๋์ด (contentBoxSize์ ๋์ผ)x- ๋ฐ์ค๋ฅผ ๊ธฐ์ค์ผ๋ก ์์นํ ์ปจํ ์ธ ์x์ขํy- ๋ฐ์ค๋ฅผ ๊ธฐ์ค์ผ๋ก ์์นํ ์ปจํ ์ธ ์y์ขํleft- ์ปจํ ์ธ ์ ์ข์ธก ๊ธฐ์ค ์์น. ํต์x์ ๋์ผtop- ์ปจํ ์ธ ์ ์๋จ ๊ธฐ์ค ์์น. ํต์y์ ๋์ผright- ์ปจํ ์ธ ์ฐ์ธก ๊ธฐ์ค ์์น.bottom- ์ปจํ ์ธ ํ๋จ ๊ธฐ์ค ์์น.
ResizeObserver ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํจ DOM ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค.
ResizeObserver ๊ฐ์ฒด๋ฅผ ๋ฐํํด์ค๋ค. ์ด๋ฅผ ํตํด ์ฝ๋ฐฑ ๋ฉ์๋ ๋ด์์๋ ResizeObserver๋ฅผ ์ฐ์์ ์ผ๋ก ๋ค๋ฃฐ ์ ์๋ค.
ResizeObserver๋ฅผ ์ปค์คํ
ํ
์ ํตํด ๊ฐํธํ๊ฒ ์ฌ์ฉํด๋ณด์.
TYPESCRIPT1 2 3 4export function useResizeObserver(): void { // }
์์ ๊ฐ์ด useResizeObserver ๋ฉ์๋๋ฅผ ์ ์ํ๋ค.
useResizeObserver๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์ ์๋์ ์ธ ์์๊ฐ ํ์ํ๋ค.
- ๋์ DOM
- ์ฝ๋ฐฑ ๋ฉ์๋
- ์ต์
์ ์ธ ์์๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ์ ์ํ์. 1๋ฒ์ ๊ฒฝ์ฐ, ์ผ๋ฐ์ ์ผ๋ก HTMLElement๊ฐ ํ์ํ์ง๋ง, ํด๋น ํ
์์๋ HTMLElement ํ์
๋ฟ๋ง ์๋๋ผ, string์ ๋ฐ์ #id, .class์ ๊ฐ์ ์ ํ์๋ก ํ๊ทธ๋ฅผ ํ์ฉํ ์ ์๋๋ก ๋ง๋ค ๊ฒ์ด๋ค.
TYPESCRIPT1 2 3 4 5 6 7 8 9 10 11 12 13 14 15import { useEffect } from "react"; export type UseResizeObserverCallback = (entry: ResizeObserverEntry) => void; /** * ResizeObserver ์ ์ฉ ํ ๋ฉ์๋ * * @param {Element | string | null} ref: Element * @param {UseResizeObserverCallback} callback: ์ฝ๋ฐฑ ๋ฉ์๋ * @param {ResizeObserverOptions} options: ์ต์ */ export function useResizeObserver(ref: Element | string | null, callback: UseResizeObserverCallback, options?: ResizeObserverOptions): void { // }
ํ๋ผ๋ฏธํฐ๋ ์์ ๊ฐ๋ค. ์ดํ ResizeObserver๋ฅผ ์ ์ธํ๊ณ ์ฝ๋ฐฑ ๋ฉ์๋๋ฅผ ํ ๋นํ๋ค.
TYPESCRIPT1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21import { useEffect } from "react"; export type UseResizeObserverCallback = (entry: ResizeObserverEntry) => void; /** * ResizeObserver ์ ์ฉ ํ ๋ฉ์๋ * * @param {Element | string | null} ref: Element * @param {UseResizeObserverCallback} callback: ์ฝ๋ฐฑ ๋ฉ์๋ * @param {ResizeObserverOptions} options: ์ต์ */ export function useResizeObserver(ref: Element | string | null, callback: UseResizeObserverCallback, options?: ResizeObserverOptions): void { useEffect(() => { const ro = new ResizeObserver((entries) => { entries.forEach(callback); }); }, [ ref, callback, options ]); }
ResizeObserver๋ฅผ ์ด๊ธฐํํ์ฌ ro ๋ณ์๋ก ํ ๋นํ๋ค.
์ดํ ref๋ก ์ง์ ํ DOM์ ํ ๋นํ๋ค.
ref๋ ์ธ ๊ฐ์ง ์ํ์ ๋ฐ๋ผ ์๋์ ๊ฐ์ ๋ถ๊ธฐ๋ฅผ ๊ฑฐ์น๋ค.
null์ผ ๊ฒฝ์ฐ -> ํจ์คํ๋ค.string์ผ ๊ฒฝ์ฐ ->document.querySelector๋ฉ์๋๋ก ํ๊ทธ๋ฅผ ์ ํํ ๋ค, ํด๋น ํ๊ทธ๋ฅผ ๋ฑ๋กํ๋ค.HTMLElement์ผ ๊ฒฝ์ฐ -> ์ด๋ฏธElement์ด๋ฏ๋ก, ์ฆ์ ๋ฑ๋กํ๋ค.
typeof ref === "string" ๊ตฌ๋ฌธ์ ํตํด ref๊ฐ ๋ฌธ์์ด์ธ์ง๋ฅผ ํ๋ณํ์ฌ ๊ตฌํํ๋ค.
ro.observe() ๋ฉ์๋๋ฅผ ํตํด ํ๊ทธ๋ฅผ ๋ฑ๋กํ ์ ์๋ค.
TYPESCRIPT1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43import { useEffect } from "react"; export type UseResizeObserverCallback = (entry: ResizeObserverEntry) => void; /** * ResizeObserver ์ ์ฉ ํ ๋ฉ์๋ * * @param {Element | string | null} ref: Element * @param {UseResizeObserverCallback} callback: ์ฝ๋ฐฑ ๋ฉ์๋ * @param {ResizeObserverOptions} options: ์ต์ */ export function useResizeObserver(ref: Element | string | null, callback: UseResizeObserverCallback, options?: ResizeObserverOptions): void { useEffect(() => { const ro = new ResizeObserver((entries) => { entries.forEach(callback); }); // DOM์ด ์ ํจํ ๊ฒฝ์ฐ if (ref) { // ref๊ฐ ๋ฌธ์์ด์ผ ๊ฒฝ์ฐ if (typeof ref === 'string') { const tag = document.querySelector(ref); // ํ๊ทธ๊ฐ ์ ํจํ ๊ฒฝ์ฐ if (tag) { ro.observe(tag, options); } } // DOM์ผ ๊ฒฝ์ฐ else { ro.observe(ref, options); } } }, [ ref, callback, options ]); }
๋ง์ง๋ง์ผ๋ก, ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง ๋ ๋๋ง๋ค ResizeObserver์ ๋ฑ๋ก์ด ์ค์ฒฉ๋์ง ์๋๋ก, ์ด๊ธฐํ ์ฝ๋๋ฅผ ๋ฃ์ด์ค๋ค.
ro.disconnect() ๋ฉ์๋๋ฅผ ํตํด ResizeObserver๋ฅผ ์ ๊ฑฐํ ์ ์๋ค.
TYPESCRIPT1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48import { useEffect } from "react"; export type UseResizeObserverCallback = (entry: ResizeObserverEntry) => void; /** * ResizeObserver ์ ์ฉ ํ ๋ฉ์๋ * * @param {Element | string | null} ref: Element * @param {UseResizeObserverCallback} callback: ์ฝ๋ฐฑ ๋ฉ์๋ * @param {ResizeObserverOptions} options: ์ต์ */ export function useResizeObserver(ref: Element | string | null, callback: UseResizeObserverCallback, options?: ResizeObserverOptions): void { useEffect(() => { const ro = new ResizeObserver((entries) => { entries.forEach(callback); }); // DOM์ด ์ ํจํ ๊ฒฝ์ฐ if (ref) { // ref๊ฐ ๋ฌธ์์ด์ผ ๊ฒฝ์ฐ if (typeof ref === 'string') { const tag = document.querySelector(ref); // ํ๊ทธ๊ฐ ์ ํจํ ๊ฒฝ์ฐ if (tag) { ro.observe(tag, options); } } // DOM์ผ ๊ฒฝ์ฐ else { ro.observe(ref, options); } } return () => { ro.disconnect(); }; }, [ ref, callback, options ]); }
์ ์ฒด ์ฝ๋๋ ์์ ๊ฐ๋ค.
CodeSandbox๋ก ๊ฐ๋จํ ์์๋ฅผ ๊ตฌํํ๋ค.
์ด์ ๊ฐ์ด ResizeObserver๋ฅผ ํ์ฉํ๋ฉด DOM์ ๋ทฐํฌํธ ๊ด๋ จ ์์๋ฅผ ์ฝ๊ฒ ๋ค๋ฃฐ ์ ์๋ค.
ํด๋น API๋ resize ์ด๋ฒคํธ๋ฅผ ๋์ฒดํ์ฌ ์ข ๋ ํจ์จ์ ์ธ ์ด๋ฒคํธ ๋์์ ๊ตฌํํ ์ ์๋ค.
๋ค์ ์ฅ์์ MutationObserver์ ๋ํด ๋ค๋ค๋ณด์.