[번역] React forwardRef와useImperativeHandle Hooks

오성준·2024년 6월 23일

React

목록 보기
1/1

원문: https://blog.stackademic.com/react-forward-ref-and-useimperativehandler-hooks-22815de9b068

이 블로그에서는 React Native에서 React forwardrefuseImperativeHandler hook의 사용법에 대해 작성하겠습니다. 시작하기 전에 부모-자식 통신을 위한 컴포넌트를 작업할 때 직면하는 문제를 살펴봅시다.

개요

아래 요구 사항을 이해해 보겠습니다. "Parent"라는 부모 컴포넌트와 "Child"라는 자식 컴포넌트가 있는데 자식 컴포넌트 내부에 선언된 메서드호출하고 부모 컴포넌트에서 일부 프로퍼티전달하여 자식 컴포넌트 내부에 있는 해당 메서드를 호출해야 한다고 가정해 보겠습니다.

이제 어떻게 이것을 수행할 수 있으며, 이를 위해 어떤 접근 방식을 따라야 하는지 생각해 봅시다. React에서 데이터를 전달하는 표준 방법은 단방향 데이터 흐름이라고도 하는 프로퍼티를 사용하는 것입니다. 그러나 자식 컴포넌트에서 부모 컴포넌트로 데이터를 다시 가져오는 것은 직접적이지는 않지만 가능합니다.

React에서 자식에서 부모로 데이터를 전송하는 방법에는 stateprops, 콜백 함수를 사용하거나 컨텍스트 훅 또는 Redux와 같은 상태 관리 라이브러리를 사용하는 등 여러 가지가 있습니다.

아래 콜백 함수 접근 방식을 살펴보겠습니다. 부모에서 자식으로 프로퍼티를 전달하는 일반적인 방법이지만 이 방식으로는 위의 문제를 해결할 수 없습니다.

import React from "react";
import { Button,Text } from "react-native";

const Child = ({onClick}) => {
    return(<>
    <Button title={'Click me'} onPress={()=>onClick('Params from child component')}></Button>
    <Text>{'Child component'}</Text>
    </>)
};

const Parent = () => {

    const callbackCall = (val) =>{
     //it will log Params from child component
      console.log(val);
    }

    return(<>
    <Child onClick={callbackCall}></Child>
    <Text>{'Parent component'}</Text>
    </>)
}
export default Parent;

위의 예시에서는 자식 컴포넌트에서 버튼을 클릭하면 onClick()을 호출하여 문자열 값부모 컴포넌트로 다시 전송하는 것을 볼 수 있습니다. 이 함수는 '콜백' 함수이며, 부모에서 자식에게 프로퍼티로 전달됩니다.

하지만 버튼이 부모 컴포넌트에 있고 부모 컴포넌트 안에 있는 버튼을 클릭할 때 자식 컴포넌트로부터 일부 데이터를 가져와야 하는 경우 이 접근 방식으로는 달성할 수 없습니다. 이제 여기서 useImperativeHandleforwardRef를 결합하여 이를 달성할 수 있습니다.

useImperativeHandle와 forwardRef

React의 useImperativeHandle hook은 forwardRef와 함께 사용할 수 있습니다. 이를 통해 부모 컴포넌트가 자식 컴포넌트의 함수와 명령적으로 상호 작용할 수 있습니다.

아래와 같이 부모 컴포넌트자식 컴포넌트가 있고 자식 컴포넌트에서 데이터를 가져와서 부모 컴포넌트에 있는 버튼을 클릭하면 부모 컴포넌트의 알림에 표시하고 싶다고 가정합니다. 이를 위해 자식 컴포넌트참조를 유지하는 ref를 생성하고 useImperativeHandle hook 안에 정의된 모든 함수부모 컴포넌트노출시킬 수 있습니다. 아래 예시를 통해 getData() 함수가 부모 컴포넌트와 함께 노출되고 그 참조 객체를 통해 자식 컴포넌트에 정의된 함수를 호출 할 수 있습니다.

import React, { useImperativeHandle } from "react";
import { useRef } from "react";
import { Button,Text } from "react-native";

const Child = React.forwardRef((props, ref) => {
    useImperativeHandle(ref, (param) => ({
        //here param will be Hii
        getData: () => `${param} send child data`
    }));
    return null;
});

const Parent = () => {

    const childRef = useRef();

    const onPressCall = () =>{
      const val = childRef.current.getData("Hii");
      //it will print hii send me child data
      console.log(val);
    }

    return(<>
    <Child ref={childRef}></Child>
    <Text>{'Parent component'}</Text>
    <Button title="ParentBtn" onPress={onPressCall}></Button>
    </>)
}
export default Parent;

따라서 위의 예제에서는 먼저 자식 컴포넌트의 ref를 생성했는데, 여기에는 childRef와 같이 자식 컴포넌트와 함께 전달되어 참조를 유지합니다.

이제 null을 반환하는 자식 컴포넌트(여기서는 요구사항에 따라 모달 또는 다른 컴포넌트가 될 수 있는 함수를 제어하기만 하면 됩니다)를 React forwardRef(상위 함수)로 감싸고 그 안에 두 개의 매개변수를 가져오는 useImperativeHandle hook을 가져옵니다. 매개변수 중 하나는 ref이고 다른 하나는 부모로부터 전송된 파라미터추출하여 위에 추가한 콜백 함수입니다. 또한 부모 컴포넌트에서 호출되어 부모 컴포넌트에 있는 버튼을 클릭할 때 문자열 값(Hii 자식 데이터 전송)을 반환하는 getData() 함수도 만들었습니다.

위에서는 버튼 클릭 시 childRef.current.getData("Hii")를 사용하여 자식 컴포넌트에 노출된 함수인 getData()를 호출하고 있습니다.

  1. forwardRef를 사용하면 부모 컴포넌트에서 자식 컴포넌트로 ref 객체를 전달하여 자식 컴포넌트 dom 요소에 액세스할 수 있습니다.

  2. useImperativeHandle을 사용하면 useImperativeHandle hook에 전달된 ref 객체수정할 수 있습니다.

useImperativeHandle 사용법

예를 들어 모달 컴포넌트가 자식 컴포넌트의 상태에 따라 숨기거나 표시하도록 설계되었지만 부모 컴포넌트에서 이 동작을 제어하려는 경우, useImperativeHandl은 이 시나리오에서 부모에 표시/숨기기 기능을 노출하여 사용할 수 있는 hook이 될 수 있습니다.

결론

useImperativeHandle hook은 모든 시나리오에서 사용할 수 있는 것은 아니지만, 프로퍼티로는 할 수 없는 방식으로 사용자 정의 컴포넌트의 내부에 액세스해야 할 때 이 hook이 완벽한 선택이 될 것입니다.

profile
React Native 개발자

0개의 댓글