일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- react-beautiful-dnd
- 완전탐색
- usedebugvalue
- React
- useLayoutEffect
- recoil
- 다이나믹프로그래밍
- 훅
- 스티커
- javascript
- 알고리즘
- 리코일
- 백준
- 리액트
- 백준 #알고리즘 #자바스크립트
- 드래그앤드롭
- 위상정렬
- Suspense
- 프로그래머스
- useContext
- 알고리즘 #프로그래머스 #코딩테스트 #자바스크립트
- 타입스크립트
- 프로그래머스 #알고리즘 #자바스크립트
- 덕타이핑
- 자바스크립트
- useRef
- 알고리즘 #코딩테스트 #프로그래머스 #자바
- Today
- Total
몽환화
[React] useImperativeHandle 물고뜯기 본문
useImperativeHandle
컴포넌트의 최상위 레벨에서 useImperativeHandle을 호출해 노출할 ref핸들을 사용자가 직접 정의할 수 있다
import { forwardRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
useImperativeHandle(ref, () => {
return {
// ... your methods ...
// ... 메서드는 여기에 작성합니다 ...
};
}, []);
// ...
useImperativeHandle(ref, createHandle, dependencies?)
ref : forwardRef 렌더 함수에서 두번째 인자로 받은 ref
createHandle : 인자가 없으며 노출하려는 ref 핸들을 반환하는 함수. 해당 ref 함수는 어떠한 유형이든 될 수 있다. 일반적으로 노출하려는 메서드가 있는 객체를 반환한다.
그러니까 기본적으로 각 컴포넌트의 DOM 노드는 비공개인데, 포커싱을 허용하기 위해 부모에 DOM 노드를 노출하는 것이 유용할 수 있어 그래서 forwardRef()로 감싸면 돼
여기서 forwardRef에 대해 알아야 한다
forwardRef : ref를 상위 컴포넌트에서 하위 컴포넌트로 전달하고 싶다면 (상위 컴포넌트에서는 접근하고 싶은 ref가 있지만 이를 직접 props로 넣어 사용할 수 없을 때) 사용한다
사실 다른 props로 전달하려면 전달할 수는 있는데 ref를 전달하는 것에 있어서 일관성을 제공하기 위해 만들어졌다!
부모 컴포넌트는 다음과 같을고얌
// 부모 컴포넌트
function Form() {
const ref = useRef(null);
function handleClick() {
ref.current.focus();
}
return (
<form>
<MyInput label="Enter your name:" ref={ref} />
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}
부모 컴포넌트에서 useRef를 사용해 ref를 만들었다. 이걸 자식 컴포넌트인 MyInput에 전달하고자 한다.
// 자식 컴포넌트
import { forwardRef } from "react";
const MyInput = forwardRef(function MyInput(props, ref) {
const { label, ...otherProps } = props;
return (
<label>
{label}
<input {...otherProps} ref={ref} />
</label>
);
});
자식 컴포넌트인 MyInput을 forwardRef로 감싸서 두번째 인자인 ref를 얘를 노출하고자 하는 DOM 노드에 전달해
이제 위에서 작성한 MyInput 컴포넌트에 ref를 전달할 수 있게 되는것
이제 ref를 전달받는것까지는 성공! 얘를 사용자 입맛대로 사용하려면 이제 useImperativeHandle을 호출하면 된다!
import { forwardRef, useImperativeHandle } from "react";
const MyInput = forwardRef(function MyInput(props, ref) {
useImperativeHandle(
ref,
() => {
return {
// ... your methods ...
// ... 메서드를 여기에 입력하세요 ...
};
},
[]
);
return <input {...props} />;
});
짜잔
근데 여기서 input에 대한 ref는 더이상 전달되지 않는다
(위의 코드와 비교해보라. ref가 없다)
왜 ?
예를 들어서 전체 input DOM 노드를 노출하지 않고 focus와 scrollIntoView의 두 메서드만을 노출하고 싶다고 가정했을 때, 이를 위해서 실제 브라우저 DOM을 별도의 ref에 유지해야 한다. 그리고 useImperativeHandle을 사용해서 부모 컴포넌트에서 호출할 메서드만 있는 핸들을 노출한다
import { forwardRef, useRef, useImperativeHandle } from "react";
const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);
useImperativeHandle(
ref,
() => {
return {
focus() {
inputRef.current.focus();
},
scrollIntoView() {
inputRef.current.scrollIntoView();
},
};
},
[]
);
return <input {...props} ref={inputRef} />;
});
그러니까 부모 컴포넌트가 MyInput의 ref를 가져오면 focus랑 scrollIntoVIew를 호출할 수 있는거고, input DOM 자체에 대한 액세스 권한은 없는거다
부모한테서 ref를 넘겨받아서 원하는 대로 수정할 수 있게 하는게 useImperativeHandle
이 ref에 원하는 값이나 액션을 정의할 수 있게 되는 것
그렇지만 ref의 과도한 사용은 자제하는게 좋다
리액트는 선언형 프로그래밍 방식인데 ref를 쓰는건 명령형 프로그래밍 방식이라 적합하지는 않다
참고자료
'Front > React' 카테고리의 다른 글
[React] Recoil 뜯어보기 (0) | 2024.05.22 |
---|---|
[React] useLayoutEffect, useDebugValue (0) | 2024.05.06 |
[React] useReducer 물고뜯기 (0) | 2024.05.03 |
[React] useContext 물고뜯기 (0) | 2024.05.02 |
[React] useRef 물고뜯기 (1) | 2024.05.01 |