forwardRef란? 그리고 고차 컴포넌트에 대하여.
forwardRef란?
챗지피티의 설명에 따르면, '자식 컴포넌트의 DOM 엘리먼트 또는
클래스 인스턴스에 접근할 수 있도록 하는 기능을 제공한다'라고 한다.
그런데 그냥 쉽게 말해서 '자식 컴포넌트에 ref를 props로 내려줘야'할 때 써야한다.
예를 들어 아래와 같은 경우, ref로 어떤 DOM 요소를 관찰하려고 하는데, 단순 jsx태그가 아니라
컴포넌트인 경우 이렇게 ref를 내려줘야한다.
이때 ref라는 이름으로 내려주면 forwardRef를 써야한다는 경고가 나온다.
props의 이름으로 아무거나 임의로 쓸 수 있는거 같지만,
'ref'같은 이름은 예약어로 forwardRef를 쓸때만 사용할 수 있는 것이다.
사용법
부모 컴포넌트에서 ref를 만들어서 내려준다. (여기서 그냥 inputRef={inputRef} 식으로 props로 내려주면 forwardRef를 쓰는 의미가 사라진다.)
// 부모 컴포넌트
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
componentDidMount() {
this.inputRef.current.focus();
}
render() {
return <MyInput ref={this.inputRef} />;
}
}
자식 컴포넌트에서:
forwardRef를 import해온 뒤
컴포넌트를 forwardRef()에 두른다.
이때 콜백 함수에 인자를 2개 꺼낼 수 있는데,
(props: 다른 props, ref ) 식으로 ref를 따로 꺼내 쓸 수 있다.
// forwardRef를 불러오기
import React, { forwardRef } from 'react';
// 자식 컴포넌트에 forwardRef()를 둘러준다.
const MyInput = forwardRef((props, ref) => (
<input ref={ref} {...props} />
));
굳이 일반 props를 쓰지않고 forwardRef를 쓰는 이유
ref 이름 제약도 없고, 캡슐화가 되어 재사용성이 좋다.
옛날에는 forwardRef가 아니라 일반 props를 아래처럼 썼었다.
<SomeComponent someRef={someRef} />
이렇게 Ref자체를 props이름으로 만들어 내려줘도 별 문제없이 작동하긴 한다.
그러나 이렇게 사용하면 자식 컴포넌트는 이제 'someRef'라는 이름으로만 써야
조작할 수 있는 컴포넌트가 되는 것이다.
자식 컴포넌트 내 ref 이름만 제한적이게 되는게 아니라,
해당 이름으로 부모에 useRef를 만들어야하는 것이기 때문에 제약이 조금 많다.
forwardRef를 썼을 땐 어디서 이 컴포넌트를 썼든 간에
ref={ ... }에 원하는대로 useRef를 만들어서 연결할 수 있다.
의미적으로 다름
props는 본래 '데이터 전달을 위한 목적'의 데이터다.
forwardRef는 하위에 있는 DOM요소를 구독하기 위함에 불과하다.
그러므로 forwardRef를 사용함으로써 의미적인 구분을 하여 코드에 대한 명료함을 올릴 수 있는 것이다.
고차 컴포넌트: 이렇게 컴포넌트를 감싸는 wrapper 함수를 말함
React.memo나 forwardRef도 모두 컴포넌트를 감싸 그 반환값으로 무언가 속성이 추가된? 느낌의 기능이다.
이런 컴포넌트를 wrapper 함수라 한다. 고차 컴포넌트는 또 한 번 기회가 되면 정리하겠다.