forwardRef
자식 컴포넌트에 ref 전달
ref를 이용해서 DOM 객체에 접근할 수 있지만 부모 컴포넌트에서 자식 컴포넌트의 DOM 객체에 접근하는 것은 허용하지 않는다.
이때 forwardRef 함수를 사용하면 부모 컴포넌트에서 생성된 ref를 자식 컴포넌트에게 전달할 수 있다. 이를 통해 부모 컴포넌트가 자식 컴포넌트의 인스턴스에 접근할 수 있도록 한다.
forwardRef 사용법
import { useEffect, useRef, forwardRef } from "react";
function ChildComponent(props, ref) {
return <input ref={ref} />;
}
const ForwardedChild = forwardRef(ChildComponent);
export default function ParentComponent() {
const inputRef = useRef();
useEffect(() => {
inputRef.current.focus();
}, []);
return (
<div>
<ForwardedChild ref={inputRef} />
</div>
);
}
useRef 훅을 호출하여 ref를 생성하고 자식 컴포넌트에게 props로 전달한다.
forwardRef 훅을 호출해 자식 컴포넌트를 감싸면 두 번째 매개변수로 부모 컴포넌트에서 설정한 ref를 참조할 수 있다.
참고로 useEffect 훅을 사용한 것은 DOM 객체가 생성되는 시점이 렌더링 이후이기 ref에 안전하게 접근하기 위해서다.
useImperativeHandle
useImperativeHandle이란?
forwardRef 훅만 사용하면 자식 컴포넌트의 내부 구조와 동작을 부모 컴포넌트에 노출시키기 때문에 두 컴포넌트 간의 결합도가 높아진다.
useImperativeHandle 훅은 필요한 메소드와 값을 선택적으로 부모 컴포넌트에 노출시킬 수 있어서 forwardRef 훅과 같이 사용하면 이 문제를 해결할 수 있다.
useImperativeHandle 사용법
import { useEffect, useRef, forwardRef, useImperativeHandle } from "react";
function ChildComponent(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
}));
return <input ref={inputRef} />;
}
const ForwardedChild = forwardRef(ChildComponent);
export default function ParentComponent() {
const inputRef = useRef();
useEffect(() => {
inputRef.current.focus();
inputRef.current.scrollIntoView(); // 에러
}, []);
return (
<div>
<ForwardedChild ref={inputRef} />
</div>
);
}
forwardRef 훅을 사용한 코드에서 자식 컴포넌트에 useImperativeHandle 훅을 호출하여 첫 번째 인수로 전달 받은 ref를 넣고 두 번째 인수로 ref 핸들을 반환하는 함수를 넣는다.
이때 내부적으로 실제 DOM input 요소의 ref는 useRef를 통해 설정해야 하기 때문에 자식 컴포넌트 안에서 input 요소에 ref를 별도로 설정한다.
ref를 통해 부모 컴포넌트에서 접근 가능한 메서드를 정의하고 별도로 설정한 ref와 연결하면 된다.
위 코드처럼 부모 컴포넌트에서 정의된 메서드인 focus는 호출할 수 있지만 그 외의 scrollIntoView 같은 정의되지 않은 메서드는 호출할 수 없다.
'기록 > TIL' 카테고리의 다른 글
[TIL] Context API와 Redux의 차이 / Redux Toolkit (0) | 2024.11.21 |
---|---|
[TIL] 상태 관리 / Redux (1) | 2024.11.20 |
[TIL] React Router(2) (0) | 2024.11.17 |
[TIL] MPA와 SPA / React Router(1) (0) | 2024.11.16 |
[TIL] Context (0) | 2024.11.15 |