React의 ref
리액트에서는 DOM 노드에 접근하기 위해 컴포넌트의 ref
라는 속성을 이용한다. 리액트에서 권장되지 않는 방법이지만, ref
를 사용해 노드의 속성을 직접 변경하는 것도 가능하다.
import React, { useRef } from "react";
const ColorBlock = () => {
const ref = useRef();
const handleClick = () => {
ref.current.style.background = 'red';
}
return (
<div>
<div ref={ref} style={{height:'50px', width:'50px', background:'black'}}></div>
<button type='button' onClick={handleClick}>CLick Me</button>
</div>
);
};
가끔은 자식 컴포넌트의 노드에 접근하기 위해 자식에게 ref
를 전달해야하는 경우가 있다. 그러나 React에서 ref
는 이미 예약된 이름이기 때문에 자식에게 prop
으로 전달되지 않는다.
const Parent = () => {
const ref = useRef();
const handleClick = () =>{
ref.current.style.background = 'red';
}
return (
<div>
<Child ref={ref}/>
<button type='button' onClick={handleClick}>Clike Me</button>
</div>
);
};
const Child = ({ref})=>{
return(
<div ref={ref} style={{height:'50px', width:'50px', background:'black'}}></div>
)
}
위 코드를 실행하면 다음과 같이 ref
는 prop
이 아니라는 경고가 나타날 것이다.
Warning: Child: `ref` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://fb.me/react-special-props)
in Child (at src/index.js:14)
in Parent (at src/index.js:30)
in App (at src/index.js:34)
ref
를 자식 컴포넌트를 전달하기 위해서는 forwardRef
함수를 사용해야 한다.
forwardRef로 자식 컴포넌트에 ref 전달하기
forwardRef
를 사용하면 자식 컴포넌트에 대한 ref
를 명시적으로 전달할 수 있다. 아래는 이전 코드의 Child
컴포넌트를 forwardRef
로 감싸준 모습이다. forwardRef
는 props
와 ref
를 매개변수로 받고 렌더 함수를 반환한다.
import React, { forwardRef, useRef } from "react";
const Parent = () => {
const ref = useRef();
const handleClick = () =>{
ref.current.style.background = 'red';
}
return (
<div>
<Child ref={ref}/>
<button type='button' onClick={handleClick}>Clike Me</button>
</div>
);
};
const Child = forwardRef((props, ref) => {
return(
<div ref={ref} style={{height:'50px', width:'50px', background:'black'}}></div>
)
});
Child
컴포넌트는 부모로부터 전달 받은 ref
를 다시 div
에 전달할 수 있게 되었다.
예시
일반적인 상황에서는 자식 컴포넌트의 ref
가 필요한 경우가 잘 없어, 어느 때 사용해야 할지 아직 감이 오지 않을 수도 있다. 보다 구체적인 예시를 위해 내가 실제로 작성한 가져와 보았다.
Game
컴포넌트는 가장 상위의 컴포넌트로 Tools
와 DrawingCanvas
컴포넌트를 자식으로 갖고, 두 자식에게 canvas
라는 이름의 객체를 props
로 전달해준다. Canvas
클래스는 생성자의 인수로 노드의 ref
를 받아 해당 노드 아래에 HTMLCanvasElement
를 삽입한다.
const Game: React.FC<GameProps> = (props) => {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const canvas = new Canvas(ref);
}, []);
return (
<>
<Tools canvas={canvas}/>
<DrawingCanvas canvas={canvas} status={status} ref={ref} />
</>
);
};
Game
아래에 직접 div
를 두어 canvas
객체를 생성할 수도 있지만 로직을 분리하기 위해 DrawingCanvas
컴포넌트 아래에 두기로 했다. 이와 같은 상황에서 div
에 ref
를 전달 하려면 forwardRef
를 사용해야 한다.
const DrawingCanvas = forwardRef<HTMLDivElement, DrawingCanvasProps>(
(props, ref) => {
//... do something
return (
<>
<div ref={ref}></div>
</>
);
}
);
참고자료
https://ko.reactjs.org/docs/forwarding-refs.html
댓글