본문 바로가기
React

forwardRef, useImperativeHandle에 대한 이해

by 붕어사랑 티스토리 2022. 11. 17.
반응형

1. 한줄요약

자식 컴포넌트의 element에 대해 ref를 따고 싶으면 forwardRef를 사용해라!

 

 

 

 

2. forwardRef에 대한 예제

 

아래와 같은 FancyButton이라는 컴포넌트가 있다고 하자

function FancyButton(props) {
  return (
    <button className="FancyButton">
      {props.children}
    </button>
  );
}

이 컴포넌트를 자식으로 두는 부모의 컴포넌트가, 저 <button>의 ref를 따고 싶다면? forwardRef를 사용하면 된다.

const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));

// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;

 

 

 

 

3. 아니 그냥 prop으로 ref주면 안돼요? 왜 저리 써야 됨?

처음 저 설명을 보고 나도 저런 생각이 들었다... 그냥 prop으로 주면 안되나?

공식문서 설명을 찾아보니 다음과 같은 내용이 있다.

 

If you use React 16.2 or lower, or if you need more flexibility than provided by ref forwarding, you can use this alternative approach and explicitly pass a ref as a differently named prop.

 

리액트 16.2 이하버전에서는 그냥 prop으로 ref를 넘겨줘도 된다고, 단 ref라는 이름말고 다른 이름으로 prop을 줘야한다.

계속 찾아서 읽다보니 왜 다른이름을 줘야하냐? 이유는 ref는 리액트에서 special 하기 때문! 이라고 한다.

 

위 내용에 관하여 공식문서에서 만든 내용이 있는데 역시나 별다른 설명이 없이 ref말고 다른이름으로 전달하세요! 라고

https://gist.github.com/gaearon/1a018a023347fe1c2476073330cc5509

 

 

뭐 어쨋든 사람들이 궁금해 하는 것은 forwadRef가 prop으로 넘겨주는거 대비 장점이 뭐냐? 라는 내용인데 더이상 설명이 없다.

 

 

다만 16.3 이상에서는 forwadRef를 쓰라고 권장한다.

 

If you use React 16.3 or higher, we recommend to use ref forwarding for these cases. Ref forwarding lets components opt into exposing any child component’s ref as their own. You can find a detailed example of how to expose a child’s DOM node to a parent component in the ref forwarding documentation.

 

 

 

나는 이에대해 비슷한 경험이 있다. 안드로이드 커스텀 ui를 개발할 때 구글에서는 ui업데이트를 메인 스레드에서 하라고 권장했다. 그런데 테스트해보니 다른 스레드에서도 업데이트가 가능한 것 이었다.

 

나는 ui퍼포먼스를 위해 다른 스레드에서 ui를 업데이트 했고 문제없이 잘 돌아갔다. 개발할땐 몰랐는데 나중에 스테빌리티 테스트를 할 때 한시간 후에 ui가 퍽하고 죽어버리는것이었다. 도대체 왜 죽나 이해를 못했는데 나중에 ui업데이트를 메인스레드에서 해 주니 해결되었다.

 

그리고 느꼈다. 개발사가 이유도 안알려주고 하라고 하면 다 이유가 있으니 하라는대로 해야된다고...

그래서 결론은 시키는대로 합시다!

 

 

 

 

 

4.자식컴포넌트에 여러개의 ref를 따고싶다면?

 

위 예시에는 하나의 ref만 따는 예제이다. 만약 자식컴포넌트의 여러 요소들에 대해 ref를 여러개 따고 싶으면?

 

useImperativeHandle 을 사용해야 된다!

 

useImperativeHandle은 자식의 여러 요소들을 오브젝트에 담에서 ref에 전달해 준다.

 

 

아래는 공식문서의 예제이다.

function FancyInput(props, ref) {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));
  return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);

여기기서 공식문서의 예제는 ref를 사용하였다. 역시나 부연설명에 위에 처럼 ref를 직접적으로 사용하는걸 피하라는 내요이 있다.

 

왜냐하면 ref는 react에서 specail하기 때문에 ☆★

 

그러므로 반드시 forwadRef와 같이 사용하라고 권장한다. 그럼 아래처럼 되시겠다!

const FancyInput = forwadRef((props, ref) => {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));
  return <input ref={inputRef} ... />;
});
FancyInput = forwardRef(FancyInput);

 

반응형

댓글