일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- 파이썬
- es6
- TypeScript
- 백엔드
- 백준
- 이슈
- 솔리디티
- BFS
- 프론트엔드
- 가상화
- docker
- kubernetes
- next.js
- 자바스크립트
- 알고리즘
- 리액트
- 이더리움
- 클라우드
- AWS
- react
- CSS
- k8s
- VUE
- HTML
- 쿠버네티스
- 타입스크립트
- 웹
- 컴퓨터공학
- 블록체인
- JavaScript
- Today
- Total
즐겁게, 코드
forwardRef로 함수 컴포넌트의 ref 전달하기 본문
토스의 첫 개발 컨퍼런스, SLASH21이 막을 올렸습니다!
저는 이런 컨퍼런스 홍보 페이지를 보면 항상 개발자 도구에 먼저 손이 가곤 하는데, 이번에는 특이하게도 페이지가 리액트로 제작되어 있어 컴포넌트를 구경하던 중 처음 보는 forwardRef
성분에 대해 궁금증을 갖게 되었습니다. 🤔
🛠 HTML 노드를 커스텀 컴포넌트로 교체하기
import { useEffect, useRef } from "react";
import Input from "./components/Input";
function App() {
const nameRef = useRef(null);
const submitRef = useRef(null);
useEffect(() => {
alert("페이지 로딩됨");
nameRef.current.focus();
}, []);
const onKeyDown = (e) => {
if (e.key === "Enter") {
submitRef.current.focus();
}
};
const submitKeyDown = () => {
alert("form submitted");
};
return (
<div className="App">
<header className="App-header">
<input
type="text"
ref={nameRef}
onKeyDown={onKeyDown}
placeholder="이름을 입력하세요"
></input>
<button ref={submitRef} onKeyDown={submitKeyDown}>
제출
</button>
</header>
</div>
);
}
export default App;
useRef
로 ref를 직접 제어해 엔터를 누르면 다음 요소로 포커스가 이동하도록 한 예시입니다.
그런데, 실제로 리액트 컴포넌트를 작성할 때는 이렇게 input 태그를 사용하기보다는 커스텀한 입력 컴포넌트를 사용하는 경우가 많습니다.
// 커스텀한 입력 컴포넌트
const CustomInput = ({ type, onKeyDown, placeholder }) => {
return (
<input
type={type}
onKeyDown={onKeyDown}
placeholder={placeholder}
></CustomInput>
);
};
// input 태그를 CustomInput 컴포넌트로 대체
return (
<div className="App">
<header className="App-header">
<CustomInput
type="text"
ref={nameRef}
onKeyDown={onKeyDown}
placeholder="이름을 입력하세요"
></CustomInput>
<button ref={submitRef} onKeyDown={submitKeyDown}>
제출
</button>
</header>
</div>
);
}
이제 입력을 받는 input 태그를 CustomInput
이라는 컴포넌트로 교체했는데요, 과연 CustomInput
컴포넌트도 useRef
와 ref를 통한 직접 제어가 가능할까요?
아! 안되네요!
ref를 통해 CustomInput
컴포넌트를 조작하려 하면 null 값을 참조하려 한다는 오류가 출력되는데, 과연 원인이 무엇일까요?
🖋 원인 - 함수 컴포넌트는 ref가 존재하지 않는다!
바로 함수 컴포넌트의 ref는 애초에 존재하지 않기 때문입니다.
그럼 ref를 통해 함수 컴포넌트를 직접 제어하는건 완전히 불가능한 일인 걸까요?
React.forwardRef
바로 이럴 때 forwardRef를 활용할 수 있습니다.
forwardRef를 사용하면 부모 컴포넌트로부터 하위 컴포넌트로 ref를 전달할 수 있는데요, 이렇게 전달받은 ref를 HTML 요소의 속성으로 넘겨줌으로써 함수 컴포넌트 역시 ref를 통한 제어가 가능해집니다.
// props 목록 뒤에 ref를 별도로 전달받는 모습입니다.
const CustomInput = React.forwardRef(({ type, onKeyDown, placeholder }, ref) => {
return (
<input
type={type}
onKeyDown={onKeyDown}
placeholder={placeholder}
// 전달받은 ref는 HTML 속성으로 전달됩니다.
ref={ref}
></input>
);
});
export default CustomInput;
또는 이렇게 사용할 수도 있습니다.
const CustomInput = ({ type, onKeyDown, placeholder }, ref) => {
return (
<input
type={type}
onKeyDown={onKeyDown}
placeholder={placeholder}
ref={ref}
></input>
);
};
// 위의 방법과 동작상 차이는 없습니다.
const forwardedRefInput = React.forwardRef(CustomInput);
export default forwardedRefInput;
TL;DR
- 커스텀 컴포넌트는 ref 속성이 존재하지 않아 아래와 같이 ref를 전달받을 수 없습니다.
// 커스텀한 입력 컴포넌트
<CustomInput
type="text"
ref={nameRef} // 함수 컴포넌트는 ref가 존재하지 않음!
></CustomInput>
따라서 컴포넌트가 ref를 전달받기 위해서는 React.forwardRef
로 컴포넌트를 감싸준 후, props 뒤에 별도로 전달된 ref를 활용합니다.
// forwardRef로 컴포넌트를 감싼 모습
const CustomInput = React.forwardRef({ type }, ref) => {
return (
<input
type={type}
// 전달받은 ref는 HTML 속성으로 전달됩니다.
ref={ref}
></input>
);
});
export default CustomInput;
'🎨 프론트엔드 > React.js' 카테고리의 다른 글
redux-saga의 call에 관해 (0) | 2021.05.26 |
---|---|
useState 똑똑하게 사용하기 (0) | 2021.05.10 |
useEffect 내에서 async 함수를 사용할 때의 주의점 (2) | 2021.04.27 |
컴포넌트 내에서 라우팅 경로와 쿼리스트링 추출하기 (0) | 2021.04.12 |
react-redux 로 상태 관리하기 - 01. 리덕스란 (0) | 2021.04.05 |