🏈

기본 사용법

 

9.2. 기본 사용법

이제 useImperativeHandle을 사용하는 방법을 알아보겠습니다. 기본적으로 useImperativeHandle은 React.forwardRef와 함께 사용됩니다. 먼저 React.forwardRef에 대해 간단히 살펴보겠습니다.
 

9.2.1 React.forwardRef

React.forwardRef는 부모 컴포넌트가 자녀 컴포넌트에게 ref를 전달할 때 사용하는 기술입니다. 부모 컴포넌트가 자녀 컴포넌트의 DOM 요소에 직접 접근해야 할 때 특히 유용하게 사용됩니다. React에서 ref prop은 HTML 엘리먼트 접근이라는 특수한 용도로 사용되기 때문에 일반적인 prop으로 사용할 수 없습니다. React 컴포넌트에서 ref를 prop으로 전달하려면 React.forwardRef를 사용해야 합니다.
 
간단한 예제로 React.forwardRef를 사용해보겠습니다. 아래의 그림과 같이 버튼을 클릭할 때 MyInput이라는 Input 컴포넌트에 포커스를 주는 예제입니다.
 
그림 9-n그림 9-n
그림 9-n
 
먼저 부모 컴포넌트인 App 컴포넌트에 useRef를 이용해서 ref를 만들고 그것을 전달하기 위해 MyInput의 ref 속성으로 넣어주었습니다.
 
import React, { useRef } from 'react'; import MyInput from './MyInput'; function App() { const inputRef = useRef(); const focus = () => { inputRef.current.focus(); }; return ( <div style={{ margin: '20px 10px' }}> <MyInput ref={inputRef} /> <button style={{ marginLeft: '10px' }} onClick={focus}>인풋 포커스</button> </div> ); };
App.js
 
ref를 전달받을 자녀 컴포넌트를 forwardRef로 감싸주면 자녀 컴포넌트는 두번째 매개변수를 갖게 되는데, 여기에 부모에게서 전달받은 ref가 들어있습니다. 자녀 컴포넌트는 전달받은 ref를 input 태그의 ref 속성으로 넣어주면 됩니다. 이제 ref는 input의 DOM 노드를 참조하게 되어 버튼이 클릭될 때마다 focus 함수를 호출할 수 있게 됩니다.
 
import { forwardRef } from 'react'; function MyInput(props, ref) { return <input ref={ref} />; }; export default forwardRef(MyInput);
MyInput.jsx
 
위와 같이 React.forwardRef를 사용하면 HTML 엘리먼트에 ref를 전달하듯 부모 컴포넌트가 자녀 컴포넌트에게 ref를 전달할 수 있게 됩니다. 일반적으로 forwardRef() 함수는 HTML 엘리먼트 대신에 사용되는 최말단 컴포넌트(ex. <Input/>, <Button/>)를 대상으로 주로 사용되며, 그보다 상위 컴포넌트에서의 사용은 권장되지 않습니다. 어떤 컴포넌트의 내부에 있는 HTML 엘리먼트의 레퍼런스를 외부에 있는 다른 컴포넌트에서 접근하도록 하는 것은 컴포넌트 간의 결합도(coupling)을 증가시켜 애플리케이션의 유지보수를 어렵게 만들기 때문입니다.
 

9.2.2 useImperativeHandle 사용하기

이제 useImperativeHandle을 React.forwardRef와 함께 사용해보겠습니다. useImperativeHandle을 사용하는 컴포넌트는 React.forwardRef로 감싸주어야 합니다. 그리고 상위 컴포넌트로부터 React.forwardRef의 두번째 매개변수로 전달받은 ref를 useImperativeHandle의 첫번째 인자 값으로 전달합니다.
 
위의 예제와 비슷하게 버튼을 클릭할 때 MyInput이라는 Input 컴포넌트에 포커스를 주면서 동시에 input 태그의 value를 포커스 되었습니다!라고 변경하는 예제를 살펴보겠습니다. 예제 코드의 실행 결과는 다음 그림과 같습니다.
 
그림 9-n2그림 9-n2
그림 9-n2
 
자식 컴포넌트인 MyInput를 보면, forwardRef() 함수로 감싸여 있고 두번째 매개변수인 ref가 useImperativeHandle의 첫 번째 인자로 들어가 있는 것을 확인할 수 있습니다.
 
import { forwardRef, useImperativeHandle, useRef } from 'react'; function MyInput(props, ref) { const inputRef = useRef(); useImperativeHandle(ref, () => ({ customFocus: () => { inputRef.current.focus(); inputRef.current.value = '포커스 되었습니다!'; }, })); return <input ref={inputRef} />; } export default forwardRef(MyInput);
MyInput.jsx
 
useImperativeHandle의 첫 번째 인자는 프로퍼티를 부여할 ref, 두 번째 인자는 객체를 리턴하는 함수입니다. 이 객체에 추가하고 싶은 프로퍼티를 정의하면 됩니다. 예시에서는 customFocus라는 메서드를 정의했고, 이 메서드를 호출하기 위해서는 사용할 곳에서 그 ref.current에 정의된 메서드를 호출하기만 하면 됩니다.
 
import React, { useRef } from 'react'; import MyInput from './MyInput'; function App() { const inputRef = useRef(); return ( <div style={{ margin: '20px 10px' }}> <MyInput ref={inputRef} /> <button style={{ marginLeft: '10px' }} onClick={() => inputRef.current.customFocus()} > 인풋 포커스 </button> </div> ); }
App.js
 
기존의 input 엘리먼트에는 customFocus라는 메서드가 없지만, useImperativeHandle에서 정의했기 때문에 사용할 수 있습니다. 이처럼 useImperativeHandle은 forwardRef 함수를 사용해서 ref를 사용하는 부모 측에서 커스터마이징된 메서드를 사용할 수 있게 해줍니다.