React 컴포넌트는 그들의 수행 상세 내용, 출력 결과를 숨김 (캡슐화)
이러한 캡슐화는 애플리케이션 레벨의 컴포넌트에게는 바람직하지만, 재사용성이 큰 말단 컴포넌트에서는 불변함
Ref forwarding은 일부 컴포넌트가 자신이 받은 ref를 자식 컴포넌트로 내려주는데 최적화되어 있음
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>
위 코드에서 FancyButton은 React.forwardFef
를 사용해서 전달받은 ref를 얻어서 렌더링되는 DOM button에 전달함
위 코드에 대한 단계적 설명
React.createRef
를 호출해서 React ref를 생성하고, ref 변수에 할당함<FancyButton ref={ref}>
아래로 전달함forwardRef(props, ref) => ...
의 두 번째 인자로 ref를 전달함<button ref={ref}>
로 내려서 전달해줌ref.current
속성은 <button>
DOM 노드를 가리킴
- 두번째 인자 ref는
React.forwardRef
호출과 함께 컴포넌트가 정의되었을 때만 존재함- 일반적인 함수나 클래스 컴포넌트는 ref 인자를 받지도 않고, props에서 사용할 수 없음
- ref forwarding은 DOM 컴포넌트 뿐만 아니라 클래스 컴포넌트의 인스턴스도 전달할 수 있음
컴포넌트 라이브러리에서 forwardRef를 사용하기 시작할 때 변경사항으로 간주하고 라이브러리의 새로운 중요 버전으로 릴리즈 해야 함
React.forwordRef
가 존재할 때 조건부로 적용하는 것도 권장하지 않음
function logProps(WrappedComponent) {
class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log('old props:', prevProps);
console.log('new props:', this.props);
}
render() {
return <WrappedComponent {...this.props} />;
}
}
return LogProps;
}
class FancyButton extends React.Component {
focus() {
// ...
}
// ...
}
// FancyButton 대신 LogProps를 내보내도 결과적으로는 FancyButton이 렌더링 됨
export default logProps(FancyButton)
prop
이 아니므로 전달되지 않음import FancyButton from './FancyButton';
const ref = React.createRef();
// 가져온 FancyButton 컴포넌트는 LogProps HOC임
// ref는 내부 FancyButton 컴포넌트 대신 LogProps를 가리킴
<FancyButton
label="Click Me"
handleClick={handleClick}
ref={ref}
/>;
React.forwardRef
API를 사용하여 내부 FancyButton 컴포넌트에 대한 refs를 명시적으로 전달받을 수 있음React.forwardRef
는 props
와 ref
매개변수를 받아 React 노드를 반환하는 렌더링 함수를 인수로 받음function logProps(Component) {
class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log('old props:', prevProps);
console.log('new props:', this.props);
}
render() {
const {forwordedRef, ...rest} = this.props;
// 사용자가 정의한 prop 'forwordedRef'를 ref로 할당함
return <Component ref={forwardedRef} {...this.props} />;
}
}
// React.forwardRef에서 제공하는 두 번째 매개변수 ref를 주의하기
// 'forwordedRef'와 같은 일반 prop으로 ref를 LogProps에 전달할 수 있음
// 'forwordedRef' prop으로 전달받은 ref를 Component의 ref에 연결할 수 있음
return LogProps.forwardRef((props, ref) => {
return <LogProps {...props} forwardedRef={ref} />;
});
}
React.forwardRef
가 인자로 받는 렌더링 함수를 사용하여 ref 전달 컴포넌트에 대해 무엇을 표시할 것인지 결정함// DevTools에 'ForwardRef'로 나타남
const WrappedComponent = React.forwardRef((props, ref) => {
return <LogProps {...props} forwardedRef={ref} />;
});
// DevTools에 'ForwardRef(myFunction)'으로 나타남
const WrappedComponent = React.forwardRef(
function myFunction(props, ref) {
return <LogProps {...props} forwardedRef={ref} />;
}
);
displayName
속성을 설정 가능함function logProps(Component) {
class LogProps extends React.Component {
// ...
}
function forwardRef(props, ref) {
return <LogProps {...props} forwardedRef={ref} />;
}
// DevTools에서 이 컴포넌트에 조금 더 유용한 표시 이름을 지정 가능함
// 예, "ForwardRef(logProps(MyComponent))"
const name = Component.displayName || Component.name;
forwardRef.displayName = `logProps(${name})`;
return React.forwardRef(forwardRef);
}