본문 바로가기
React Native

[RN] forwardRef를 사용하는 이유

by 어느새벽 2025. 2. 21.

1. forwardRef 없이 구현하는 경우

import React, { useRef, useState } from "react";
import { TextInput, View, Button } from "react-native";

// CustomInput 컴포넌트 (ref를 사용하지 않음)
const CustomInput = ({ value, onChangeText }) => {
  return (
    <TextInput
      value={value}
      onChangeText={onChangeText}
      placeholder="입력하세요"
      style={{
        height: 40,
        borderColor: "gray",
        borderWidth: 1,
        paddingHorizontal: 10,
      }}
    />
  );
};

const App = () => {
  const [text, setText] = useState("");
  const inputRef = useRef<TextInput>(null);

  const focusInput = () => {
    if (inputRef.current) {
      inputRef.current.focus(); // 작동하지 않음! ref가 전달되지 않았기 때문.
    }
  };

  return (
    <View style={{ padding: 20 }}>
      {/* CustomInput을 사용하지만 ref를 직접 전달할 수 없음 */}
      <CustomInput value={text} onChangeText={setText} />
      <Button title="포커스하기" onPress={focusInput} />
    </View>
  );
};

export default App;

 

❌ 문제점

  1. CustomInput은 TextInput을 감싸고 있지만, 부모가 ref를 직접 접근할 수 없음.
  2. focusInput을 호출해도 TextInput에 focus()를 줄 수 없음.
  3. 상태 (value, onChangeText)를 전달해야 하므로 코드가 다소 복잡해질 수 있음.

2. forwardRef를 사용한 경우

import React, { forwardRef, useRef } from "react";
import { TextInput, View, Button } from "react-native";

// forwardRef를 사용하여 ref를 TextInput에 연결
const CustomInput = forwardRef<TextInput, { placeholder?: string }>(
  ({ placeholder }, ref) => {
    return (
      <TextInput
        ref={ref} // 부모로부터 전달받은 ref를 연결
        placeholder={placeholder}
        style={{
          height: 40,
          borderColor: "gray",
          borderWidth: 1,
          paddingHorizontal: 10,
        }}
      />
    );
  }
);

const App = () => {
  const inputRef = useRef<TextInput>(null);

  const focusInput = () => {
    if (inputRef.current) {
      inputRef.current.focus(); // ref를 이용해 TextInput에 포커스 설정
    }
  };

  return (
    <View style={{ padding: 20 }}>
      <CustomInput ref={inputRef} placeholder="입력하세요" />
      <Button title="포커스하기" onPress={focusInput} />
    </View>
  );
};

export default App;

 

✅ 개선점

  1. CustomInput 내부의 TextInput에 부모가 직접 ref를 전달할 수 있음.
  2. 부모에서 focus(), clear(), scrollToEnd() 등의 메서드를 사용할 수 있음.
  3. 상태(value, onChangeText)를 부모에서 관리하지 않아도 됨.

3. 결론: forwardRef가 필요한 경우

forwardRef 없이도 구현할 수 있지만, 특정 UI 요소(TextInput, ScrollView, FlatList 등)에 직접 접근해야 할 때는 forwardRef가 필요함.

언제 forwardRef를 써야 할까?

  • 부모가 자식의 특정 요소(TextInput, ScrollView)에 focus(), clear(), scrollTo() 같은 메서드를 호출해야 할 때
  • useImperativeHandle과 함께 사용하여 자식 컴포넌트의 특정 기능을 부모가 호출할 수 있도록 할 때
  • HOC(고차 컴포넌트)에서 ref를 올바르게 전달할 때

즉, "부모가 자식의 내부 요소에 직접 접근해야 한다면 forwardRef를 사용하고, 그렇지 않다면 상태(props)만으로 관리하는 게 좋다"