React (useImperativeHandle & forwardRef)

Jeonghun·2023년 5월 26일
2

React

목록 보기
10/21


React의 useImperativeHandle과 forwarRef

(아, 이 녀석 이름부터 어렵다..!)
React에서 컴포넌트의 인스턴스 값에 사용자 지정 메소드를 추가하거나 특정 값을 가져오기 위해 useImperativeHandle과 forwardRef를 사용할 수 있다. 이들은 서로 연관되어 작동하며, 주로 컴포넌트의 내부 값을 외부에서 접근 가능하게 하거나, 부모 컴포넌트에서 자식 컴포넌트의 메서드를 호출하는 등의 상황에서 사용된다. 우선, forwardRef에 대해 알아보자.

- Forward Ref

🤔 Forward Ref는 뭘까?
React에서는 ref(useRef)를 사용하여 DOM 요소 또는 컴포넌트 인스턴스에 직접 접근할 수 있다. 하지만 이는 일반적으로 부모 컴포넌트에서 자식 컴포넌트의 DOM 요소나 인스턴스에 직접 접근하는 것을 허용하지 않는다. 이 때 사용하는 것이 바로 forwardRef 라고 할 수 있겠다.

📌 forwardRef를 사용해보자

forwardRef는 부모 컴포넌트에서 생성된 ref를 자식 컴포넌트에게 전달하며, 이를 통해 부모 컴포넌트가 자식 컴포넌트의 인스턴스에 접근할 수 있도록 한다.

import React, { forwardRef } from 'react'; // import

// forwardRef는 props와 ref를 인자로 받는 함수형 컴포넌트를 반환한다.
const MyComponent = forwardRef((props, ref) => (
  // parent 컴포넌트로 부터 받은 ref를 input 요소에 연결
  <input ref={ref} />
));

// parent 컴포넌트
function ParentComponent() {
  const inputRef = useRef();

  useEffect(() => {
    inputRef.current.focus();
  }, []);

  // useRef를 사용하여 MyComponent로 ref 전달
  return <MyComponent ref={inputRef} />;
}

위 코드에서 ParentComponent는 useRef를 사용하여 ref를 생성하고, 이 ref를 MyComponent에게 전달한다. MyComponent는 forwardRef를 사용하여 부모로부터 받은 ref를 내부의 input 요소에 연결하고 있다. 이렇게 하면 ParentComponent에서 inputRef를 통해 직접 input 요소를 조작할 수 있다.

- useRef vs fowardRef

🤔 useRef와 Forward Ref는 어떻게 다른가?
위에서 말했듯, useRef는 컴포넌트 내부에서 ref를 생성하고 사용하는 데 사용되며, forwardRef는 부모 컴포넌트로부터 받은 ref를 자식 컴포넌트에게 전달하는 데 사용됩니다. useRef로 생성된 ref는 컴포넌트 내부에서만 사용되지만, forwardRef를 통해 전달된 ref는 부모 컴포넌트에서도 접근할 수 있다.

- Forward Ref의 문제..

forwardRef는 자식 컴포넌트의 내부 구조와 동작을 부모 컴포넌트에 노출시키기 때문에 컴포넌트 간의 강한 결합을 초래할 수 있다. 또한, 자식 컴포넌트가 변경되면 부모 컴포넌트도 함께 변경될 수 있는 문제점을 가진다. 이러한 문제점을 해결하기 위해 React에서는 'useImperativeHandle' 훅을 제공한다.

- useImperativeHandle

🤔 이름부터 어려운 넌 도대체 어따 쓰는거니?
useImperativeHandle은 부모 컴포넌트로 노출되는 인스턴스 값을 직접 커스터마이징할 수 있게 해준다. 이를 사용하면 자식 컴포넌트는 필요한 메소드와 값을 선택적으로 부모 컴포넌트에 노출시킬 수 있다.

📌 useImperativeHandle의 사용

import React, { useImperativeHandle, forwardRef } from 'react'; // import

const MyComponent = forwardRef((props, ref) => {
  useImperativeHandle(ref, () => ({
    focus: () => {
      // 커스텀 focus 메소드
    }
  }));
  // ...
});

// Parent 컴포넌트
function ParentComponent() {
  const myRef = useRef();

  useEffect(() => {
    myRef.current.focus(); // focus 메소드 사용
  }, []);

  return <MyComponent ref={myRef} />;
}

위 코드에서 useImperativeHandle을 사용하여 MyComponent의 ref 인스턴스 값에 focus 메소드를 추가하였다. 그로인해, ParentComponent에서는 myRef.current.focus()를 호출하여 MyComponent의 focus 메소드를 직접 호출할 수 있다. 이렇게 하면 ChildComponent의 내부 구조와 동작이 완전히 노출되지 않으므로, 컴포넌트 간의 결합도를 낮추고 유지 관리를 용이하게 할 수 있다.


이상으로 useImperativeHandle과 forwardRef에 대해 알아보았다. 이러한 기능들은 항상 필요한 것은 아니지만, 특정 상황에서 매우 유용하게 사용될 수 있다. 하지만 컴포넌트 간의 문제를 야기할 수 있으므로 사용법을 숙지하고, 주의해서 사용하도록 하자.

profile
안녕하세요, 프론트엔드 개발자 임정훈입니다.

3개의 댓글

comment-user-thumbnail
2023년 12월 3일

부모요소에서 props로 ref를 넘겨주는 방식과 어떤차이가 있을까요?

1개의 답글