일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 1분코딩
- Adobe
- VW
- 이클립스 소스 비교 안보일 때
- React
- ref전달하기
- Eclipse Compare View
- JavaScript
- 이클립스
- tomcat
- Study
- TaskRunner
- error
- animation
- css
- java
- CSS3
- 자바스크립트
- html
- SSR
- Sass
- ref
- frontend
- npm
- Eclipse Bug
- 보일러플레이트
- next.js
- gulp
- Eclipse
- 정적웹사이트
- Today
- Total
프론트 개발 블로그
Forwarding Refs (React.forwardRef) 본문
Refs 전달하기
React.forwardRef 는 부모 컴포넌트에서 자식 컴포넌트로 ref 를 전달하여 부모가 자식 ref 를 참조 하는 기술입니다.
- DOM 컴포넌트에 Refs 전달하기
- 컴포넌트 라이브러리 관리자를 위한 참고 사항
- 고차 컴포넌트(HOC)에서의 forwarding Refs
- 개발자도구(DevTools)에 사용자 지정 이름 표시하는 방법
이 기법은 잘 사용되지 않지만, 아래의 두 시나리오에서는 특히 유용합니다.
- DOM 엘리먼트로 ref 전달하기
- 고차 컴포넌트(HOC) 로 ref 전달하기
DOM 컴포넌트에 Refs 전달하기
1
2
3
4
5
6
7
|
function FancyButton(props) {
return(
<button className="FancyButton">
{props.children}
</button>
);
}
|
React 컴포넌트는 렌더링 된 출력을 포함하여 내부적인 디테일을 숨깁니다.
FancyButton 컴포넌트를 사용하는 다른 컴포넌트는 일반적으로 내부 button DOM 요소에 대한 ref 를 가져올 필요가 없습니다.
이는 컴포넌트가 서로의 DOM 구조에 너무 많이 의존하는 것을 방지하기 때문입니다.
이러한 캡슐화는 FeedStory 또는 Comment 컴포넌트와 같은 애플리케이션-레벨 컴포넌트에 바람직하지만,
Fancybutton 또는 MyTextInput 과 같이 재사용 가능성이 높은 'leaf' 컴포넌트에서는 불편할 수가 있습니다.
Ref forwarding 은 일부 컴포넌트가 ref 정보를 하위 컴포넌트에 전달하는 op-in 기능입니다.
* opt-in : 수신에 동의하는 것.
아래 예제에서 FancyButton 컴포넌트는 React.forwardRef 를 사용하여 전달된 ref 를 얻고,
그런 다음 렌더링 하는 DOM button 으로 전달합니다.
1
2
3
4
5
6
7
8
9
|
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
//DOM button 에 대한 ref 를 직접 가져올 수 잇습니다.
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
|
FancyButton 컴포넌트이 기본 button DOM 노드에 대한 ref 를 가져와 필요한 경우 사용할 수 있습니다.
마치 DOM button 을 직접 사용하는 것과 같습니다.
코드 단계별 설명
1. React.forwardRef() 를 호출하여, React ref 를 만들고 ref 변수에 할당 합니다.
2. ref 를 JSX 속성을 통해, <FancyButton ref={ref} 에 전달합니다.
3. React 는 ref 를 forwardRef 의 함수의 두번째 인수로 전달합니다.
4. 이 ref 인수를 JSX 속성을 통해, <button ref={ref}> 로 전달합니다.
5. ref 가 부착되면, ref.current 는 <button> 의 DOM 노드에 가리키게 됩니다.
주의!
두번째 ref 인수는 React.forwardRef() 호출로 컴포넌트를 정의 할 때만 존재합니다.
일반 함수 또는 클래스 컴포넌트는 ref 인수를 받지 않으며, ref 는 porps 에서도 사용할 수 없습니다.
Ref forwarding 은 DOM 컴포넌트로 제한되지 않습니다.
컴포넌트 라이브러리 관리자를 위한 참고 사항
컴포넌트 라이브러리에서 forwardRef 를 사용하기 시작하면, 이를 브레이킹 체인지로 취급하고 라이브러리를 새로운 major 버전을 릴리즈해야 합니다.
이는 라이브러리에 눈에 띄게 다른 동작 (예: 참조가 할당되는 항목 및 내보내는 유형) 이 있을 가능성이 높고,
이로 인해 이전 동작에 의존하는 앱 및 기타 라이브러리가 손상 될 수 있기 때문입니다.
React.forwardRef 가 존재할 떄 존건부로 적용하는 것도 같은 이유로 권장되지 않습니다 :
라이브러리의 동작방식을 변경하고 사용자가 React 자체를 업그레이드 할 떄 앱을 손상시킬 수 있습니다.
고차 컴포넌트(HOC) 에서의 forwarding Refs
이 기술은 고차 컴포넌트에서 특히 유용할 수 있습니다.
고차 컴포넌트를 사용할 경우 바깥 컴포넌트에 ref 를 준다고 해서, 하위 컴포넌트에게 까지 전달되지 않습니다.
그럴 때 forwardRef API 를 사용할 수 있습니다.
아래는 콘솔에 log 를 기록하는 HOC 컴포넌트입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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;
}
|
logProps 고차 컴포넌트는 모든 props를 래핑하는 컴포넌트를 전달하므로 렌더링 된 아웃풋은 동일합니다.
예를 들어, 이 고차 컴포넌트를 사용하여 FancyButton 컴포넌트에 전달되는 모든 props 를 기록할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
|
class FancyButton extends React.Component {
focus() {
// ...
}
// ...
}
// FancyButton 을 내보내는 대신, LogProps 를 내보냅니다.
// 그래도 FancyButton 을 렌더링합니다.
export default logProps(FancyButton);
|
ref 는 props 가 아니기 때문에, ref 는 통과되지 않습니다.
key 와 마찬가지로 React 에서 다르게 처리 됩니다.
HOC 에 ref 를 추가하면, ref 는 래핑된 컴포넌트가 아닌 가장 바깥쪽 컨테이너 컴포넌트를 참조합니다.
즉, FancyButton 컴포넌트용 ref 가 실제로는 LogProps 컴포넌트에 붙습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import FancyButton from './FancyButton';
const ref = React.createRef();
// 가져온 FancyButton 컴포넌트는 LogProps HOC 입니다.
// 렌더링 된 출력이 동일하더라도
// ref 는 내부 FancyButton 컴포넌트 대신 LogProps 를 가리킵니다.
// 이것은 우리가 ref.current.focus() 를 불러올 수 없다는 것을 의미합니다.
<FancyButton
label="Click Me"
handleClick={handleClick}
ref={ref}
/>;
|
다행히도, React.forwardRef API 를 사용하여 ref 를 내부 FancyButton 컴포넌트로 명시적으로 전달할 수 있습니다.
React.forwardRef 는 props 와 ref 를 매개변수로 받고, React 노드를 반환하는 render 함수를 받습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import React from 'react';
function logProps(Component) {
class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log('old props:', prevProps);
console.log('new props:', this.props);
}
render() {
const {forwardedRef, ...rest} = this.props;
// 사용자 정의 props 'forwardedRef'를 ref 로 할당
return <Component ref={forwardedRef} {...rest} />;
}
}
// 1. React.forwardRef 에서 제공하는 두번째 매개변수 'ref'에 유의
// 2. LogProps 에 prop 으로 전달할 수 있습니다.
// 3. 그런 다음 컴포넌트에 연결할 수 있습니다.
return React.forwardRef((props, ref) => {
return <LogProps forwardedRef={ref} {...props} />;
});
}
export default logProps(FancyButton);
|
개발자도구(DevTools)에 사용자 지정 이름 표시하는 방법
React.forwardRef() API는 렌더링 함수를 받습니다.
React DevTools는 해당 함수를 사용하여 ref forwarding 된 컴포넌트에 표시할 내용을 결정합니다.
1
2
3
4
5
6
7
8
|
// ...
// 위의 코드 생략
return React.forwardRef(
function myFunction(props, ref) {
return <LogProps forwardedRef={ref} {...props} />;
}
);
|
래핑하는 컴포넌트를 포함하도록 함수의 displayName 속성을 설정할 수도 있습니다.
1
2
3
4
5
6
7
8
9
|
// ... 코드 생략
function forwardRef(props, ref) {
return <LogProps forwardedRef={ref} {...props} />;
}
const name = Component.displayName || Component.name;
forwardRef.displayName = `logProps(${name})`;
return React.forwardRef(forwardRef);
|
정리하면,
1. ref 는 DOM 엘리먼트에 접근하거나, 클래스 컴포넌트의 인스턴스에 접근하자고자 할 때 사용한다.
2. ref 는 props처럼 하위 컴포넌트로 전달되지 않는다.
3. forwardRef API는 상위 컴포넌트에서 하위 컴포넌트에 ref 를 전달할 때 사용하는 기술이다.
4. HOC(고차 컴포넌트)에서 하위 컴포넌트의 ref 로 접근하고자 할 때 forwardRef API를 사용하면 유용하다.
궁금증?
1. 공식문서에 사용되는 const 에 하당하여 forwardRef 를 사용하는 방법과 logProps 컴포넌트 내부에서 사용된 forwardRef 방식 중에 어떤 코드처럼 작성해야 하나?
2. 고차 컴포넌트 예시 코드처럼 고차 컴포넌트를 작성할 때 꼭 함수 컴포넌트 안에서 사용해야 하나?
A. 아래의 답변에서, 알 수 있듯이 고차 컴포넌트는 함수이다. 부작용이 없는 순수 함수로 여러개의 인수도 가질 수 있다.
3. 고차 컴포넌트란 것이 무엇인가?
A. 일반적으로 프로그래밍에서 같은 코드를 반복해서 사용할 때, 함수로 만들어 사용하고는 했다.
고차 컴포넌트는 컴포넌트에서 반복된 로직을 추상화 시켜 공통 기능으로 분리한 것이다.
고차 컴포넌트는 간단히 말해서, 컴포넌트를 취하여 준비한 기능을 수행한 후, 새로운 컴포넌트로 반환하는 함수이다.
'React' 카테고리의 다른 글
windowing 라이브러리 (0) | 2021.01.05 |
---|---|
Ref 와 DOM (0) | 2020.12.17 |
Context API (0) | 2020.12.10 |
[Errer] name can no longer contain capital letters (0) | 2020.10.28 |
What is StrictMode in React? (0) | 2020.10.27 |