Polymer -> React 리펙토링을 진행하면서 useRef를 사용한 경우를 정리해보려고 한다.
보통
useRef
는 DOM Element에 접근하여 width, height, value 값 등을 컨트롤 할 수 있다.
Canvas 관련 컴포넌트를 리엑트로 리펙토링하면서
<canvas>
엘리먼트를 접근해서 크기 변경, text, line, image를 그리도록 구현했다.
const App = () => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const [ctx, setCtx] = useState<CanvasRenderingContext2D | null>(null);
// ... 다른 상태 값
useEffect(() => {
if (!canvasImagesRef.current) return;
const canvas = canvasImagesRef.current;
setCtx(canvas.getContext("2d"));
}, [canvasRef]);
return (
<>
/* ... */
<canvas
ref={canvasRef}
/>
</>
);
}
위 canvas 컴포넌트에서 Map 데이터 구조를 사용하는 로직이 있는데
이때 useState 훅으로 선언한 변수가 아닌 일반적으로 선언된 변수가
리랜더링 되면서 초기화 되어 로직에 영향을 주었다.
(undefined가 계속 발생해서 삽질을 많이 함...)
const App = () => {
const map = new Map<string, any>(); // 이 부분
// ... 다른 상태 값
// 임의로 데이터 주입
useEffect(() => {
map.set("key1", "abc");
}, []);
const fun1 = () => {
const result = map.get("key1");
console.log(`result: ${JSON.stringify(result, null, 2)}`);
}
// ...
return (
<>
/* ... */
</>
);
}
new Map<string, any>()
로 계속 새롭게 생성되었다.계속 리랜더링 되더라도 map 객체가 초기화가 되지 않도록 useRef로 값을 할당하였다.
useRef 값으로 선언된 상태(예제에서 map)가 변경 되더라도 화면은 리랜더링 되지 않는다.
const App = () => {
const map = useRef<Map<string, any>>(new Map<string, any>()); // 이 부분
// ... 다른 상태 값
// 임의로 데이터 주입
useEffect(() => {
map.set("key1", "abc");
}, []);
const fun1 = () => {
const result = map.current.get("key1");
console.log(`result: ${JSON.stringify(result, null, 2)}`);
// ...
}
// ...
return (
<>
/* ... */
</>
);
}