d3와 react를 사용할 때에 유용하게 쓰일 수 있는 몇 가지 custom hooks이 있다.
useResizeObserver
d3로 만든 차트가 반응형으로 작동하도록 하는 hooks이다.
해당 html요소를 관찰하다 크기변화가 발생하면 내부의 callback을 실행한다.
svg의 width가 100%여야 정상적으로 작동한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import { useEffect, useState } from "react"; import ResizeObserver from "resize-observer-polyfill";
export const useResizeObserver = (ref) => { const [dimensions, setDimensions] = useState(null); useEffect(() => { const observeTarget = ref.current; const resizeObserver = new ResizeObserver((entries) => { entries.forEach((entry) => { setDimensions(entry.contentRect); }); }); resizeObserver.observe(observeTarget); return () => { resizeObserver.unobserve(observeTarget); }; }, [ref]); return dimensions; };
export default useResizeObserver;
|
usePrevValue
이전 렌더링의 값을 저장하는 hooks이다.
useEffect 내부에서 조건부 작업을 할 경우에 사용하면 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13
| import { useEffect, useRef } from "react";
function usePrevValue(value) { const prevRef = useRef(null);
useEffect(() => { prevRef.current = value; });
return prevRef.current; }
export default usePrevValue;
|
useDebounce
d3에는 수많은 이벤트가 발생한다!
zoom 이벤트나 위에서 언급한 useResizeObserver의 resize이벤트등의 요청을 줄일 수 있는 hook이다.
delay 안에 새로운 이벤트가 발생하면 기존의 값을 리턴한다.
마지막 요청 이후 delay만큼의 시간이 지나면 새롭게 세팅된 값을 리턴한다.
즉 디바운스를 hook으로 만들었다!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import { useEffect, useState } from "react";
export const useDebounce = (value, delay) => { const [debouncedValue, setDebouncedValue] = useState(value); useEffect(() => { const handler = setTimeout(() => { setDebouncedValue(value); }, delay);
return () => { clearTimeout(handler); }; }, [value, delay]); return debouncedValue; };
export default useDebounce;
|
적용하기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const App = ({ data }) => { const containerRef = useRef(); const wrapperRef = useRef(); const dimensions = useResizeObserver(wrapperRef); const resize = useDebounce(dimensions, 200);
useEffect(() => { const svg = select(svgRef.curent); const container = select(containerRef.current);
if (!resize) return;
const { width, height } = resize; svg.attr("width", width).attr("height", height); }, [data, resize]);
return ( <div ref={containerRef}> <svg ref={svgRef} /> </div> ); };
|