React: ref와 forwardRef, useImperativeHandle

바다·2023년 7월 9일
0

react

목록 보기
8/10
post-thumbnail

리액트에서 부모 컴포넌트가 자식 컴포넌트의 HTML요소를 ref로 지정하고, 해당 HTML요소에 접근하여 이벤트를 다루는 방법에 대해 공부한 내용을 정리해보고자 한다.

1. forwardRef

리액트에서 ref을 prop로 사용하려면 React에서 제공하는 forwardRef를 사용해야한다.

typescript에서 forwardRef 사용 예시

  • 부모 컴포넌트 : Parent.tsx
const Parent =()=>{
	const inputRef= useRef<HTMLInputElement>(null);
  //....
  
  return(
  //...
    <MyInput ref={inputRef}/>
  )
}
  • 자식 컴포넌트 : MyInput.tsx

import React from 'react'

// forwardRef 함수에 제네릭으로 ref와 props의 타입을 명시
 // ref type :HTMLInputElement 
// props  type :React.InputHTMLAttributes<HTMLInputElement>
const MyInput = React.forwardRef<HTMLInputElement, React.InputHTMLAttributes<HTMLInputElement>>(
  (props, ref) => {
    // input 요소에 ref와 props를 적용하여 반환
    return <input ref={ref} {...props} />
  }
)
  • props가 필요없을 경우
const MyInput = React.forwardRef<HTMLInputElement>>(
  (_, ref) => ...

2. useImperativeHandle

1) useImperativeHandle?

useImperativeHandle 은 리액트 훅 중 하나로, 부모 컴포넌트에게 노출할 ref 핸들을 사용자가 직접 정의할 수 있게 (ref로 노출 시키는 노드의 일부 메서드만 노출할 수 있게) 해주는 훅이다.

useImperativeHandle는 부모 컴포넌트가 ref를 핸들하는 것을 정의하는 것이기 때문에 부모 컴포넌트가 ref에 접근할 수 있도록 해주는 forwardRef와 함께 사용해야한다.

2) 사용방법

js에서 사용하기

  • MyInput.jsx
import { forwardRef, useImperativeHandle, useRef } from 'react';

const MyInput = forwardRef((props, ref)=> {
  const inputRef = useRef();
  useImperativeHandle(ref, () => {
    return {
      focus: (f) =>{
         if(f) inputRef.current?.focus();
      },
      scrollIntoView: () => {
        inputRef.current?.scrollIntoView();
      }
    };
  }, []);
  return <input {...props} ref={inputRef} />;
});
  • Parent.jsx
const Parent =()=>{
	const inputRef= useRef<InputHandle>(null);
  //....
  	const handleFocus =(f)=>{
    	inputRef.current?.focus(f);
    };
  	const scrollIntoView =()=>{
    inputRef.current?.scrollIntoView()}
  return(
  //...
    <MyInput ref={inputRef}/>
	<button onClick={()=>handleFocus(true)}>focus</button>
	<button onClick={()=>handleFocus(false)}>unFocus</button>
	<button onClick={scrollIntoView}>focus</button>
  )
}

typesciprt 에서 사용하기

  • MyInput.tsx
import { forwardRef, useImperativeHandle, useRef } from 'react';
export type InputHandle ={
	focus:(f:boolean)=>void,
  	scrollIntoView :()=>void,
}
const MyInput = forwardRef<InputHandle,React.InputHTMLAttributes<HTMLInputElement> >((props, ref)=> {
  const inputRef = useRef();
  useImperativeHandle(ref, () => {
    return {
      focus: (f:boolean) => {
        if(f) inputRef.current?.focus();
      },
      scrollIntoView: () => {
        inputRef.current?.scrollIntoView();
      },
    };
  }, []);
  return <input {...props} ref={inputRef} />;
});
  • Parent.tsx
const Parent =()=>{
	const inputRef= useRef<InputHandle>(null);
  //....
  	const 
  return(
  //...
    <MyInput ref={inputRef}/>
	<button onClick={()=>handleFocus(true)}>focus</button>
	<button onClick={()=>handleFocus(false)}>unFocus</button>
	<button onClick={scrollIntoView}>focus</button>
  )
}

⚠️typescript에서 useImperativeHandle을 사용 시 주의할 점은 js에서 사용할때와 다르기 ref에 대한 타입을 HTMLElement가 아니라 useImperativeHandle로 지정하는 메서드를 속성으로 가지는 타입(ex:InputHandle)으로 지정해주어야한다.

profile
🐣프론트 개발 공부 중 (우테코 6기)

0개의 댓글