본문 바로가기
React

[React] forwardRef: 자식 컴포넌트에 ref를 전달하는 방법

by 슥짱 2022. 5. 23.

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>
    )
  }

 

위 코드를 실행하면 다음과 같이 refprop이 아니라는 경고가 나타날 것이다.

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로 감싸준 모습이다. forwardRefpropsref를 매개변수로 받고 렌더 함수를 반환한다.

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 컴포넌트는 가장 상위의 컴포넌트로 ToolsDrawingCanvas 컴포넌트를 자식으로 갖고, 두 자식에게 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 컴포넌트 아래에 두기로 했다. 이와 같은 상황에서 divref를 전달 하려면 forwardRef를 사용해야 한다.

const DrawingCanvas = forwardRef<HTMLDivElement, DrawingCanvasProps>(
  (props, ref) => {

  //... do something

    return (
      <>
        <div ref={ref}></div>
      </>
    );
  }
);

 


참고자료

https://ko.reactjs.org/docs/forwarding-refs.html

 

Forwarding Refs – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

댓글