React Native 에서 Text 컴포넌트의 문장의 수를 알아내는 법

eeennsu·2026년 6월 29일

React Native

목록 보기
58/98

개요

onTextLayout은 React Native <Text> 컴포넌트의 prop이다. 텍스트가 화면에 실제로 레이아웃(배치)될 때마다 호출되며, 각 줄(line) 단위의 위치·크기 정보를 콜백으로 전달한다. JS 측에서 미리 알 수 없는 "텍스트가 몇 줄로 나뉘는가", "각 줄의 폭이 얼마인가" 같은 정보를 네이티브 측정 결과 그대로 받아올 수 있다는 점이 핵심이다.

<Text onTextLayout={(e) => console.log(e.nativeEvent.lines)}>
  측정하고 싶은 텍스트
</Text>


콜백 타입

콜백은 TextLayoutEventData를 담은 합성 이벤트를 받는다.

type TextLayoutEvent = NativeSyntheticEvent<TextLayoutEventData>;

interface TextLayoutEventData {
  lines: TextLayoutLine[];
}

interface TextLayoutLine {
  text: string;       // 해당 줄에 실제로 렌더링된 텍스트
  x: number;          // 줄의 x 좌표 (Text 기준)
  y: number;          // 줄의 y 좌표 (Text 기준)
  width: number;      // 줄의 폭
  height: number;     // 줄의 높이
  ascender: number;   // 베이스라인 위 상단까지의 거리
  descender: number;  // 베이스라인 아래 하단까지의 거리
  capHeight: number;  // 대문자 높이
  xHeight: number;    // 소문자 x 높이
}

lines 배열의 길이가 곧 실제로 렌더링된 줄 수이다. numberOfLines로 잘린 경우에는 잘린 후의 줄 수가 반영된다.

호출 시점

  • 텍스트가 최초로 레이아웃될 때 호출된다.
  • 폰트 크기, 컨테이너 폭, 텍스트 내용 등 레이아웃에 영향을 주는 값이 바뀌어 다시 측정되면 그때마다 다시 호출된다.
  • 따라서 콜백이 여러 번 불릴 수 있으므로, 동일 결과에 대한 중복 처리를 막는 가드가 필요할 수 있다.



주요 활용 사례

1. "더보기 / 접기" 구현

numberOfLines로 제한한 텍스트가 실제로 잘렸는지를 판별할 때 쓴다. 제한 없이 한 번 측정한 뒤 줄 수가 임계값을 넘는지 확인하는 패턴이다.

function ExpandableText({ children }: { children: string }) {
  const [needsExpand, setNeedsExpand] = useState(false);
  const [expanded, setExpanded] = useState(false);
  const measured = useRef(false);

  return (
    <View>
      <Text
        numberOfLines={expanded ? undefined : 3}
        onTextLayout={(e) => {
          // 최초 측정 시 한 번만 줄 수 판별
          if (measured.current) return;
          measured.current = true;
          if (e.nativeEvent.lines.length > 3) {
            setNeedsExpand(true);
          }
        }}
      >
        {children}
      </Text>

      {needsExpand && (
        <Text onPress={() => setExpanded((v) => !v)}>
          {expanded ? '접기' : '더보기'}
        </Text>
      )}
    </View>
  );
}

주의: numberOfLines로 잘린 상태에서는 lines.length가 제한값을 넘지 않는다. 잘림 여부를 정확히 판별하려면 제한 없이 측정하는 별도 단계를 두거나, onTextLayout과 numberOfLines의 호출 순서를 고려해 설계해야 한다.


2. 줄별 좌표 기반 데코레이션

각 줄의 x, y, width, height를 이용해 줄마다 하이라이트 배경, 밑줄, 오버레이 등을 절대 위치로 그릴 수 있다.

<View>
  <Text onTextLayout={(e) => setLines(e.nativeEvent.lines)}>
    {content}
  </Text>
  {lines.map((line, i) => (
    <View
      key={i}
      style={{
        position: 'absolute',
        left: line.x,
        top: line.y,
        width: line.width,
        height: line.height,
        backgroundColor: 'rgba(255,235,59,0.3)',
      }}
    />
  ))}
</View>

3. 텍스트 측정값 수집

폰트 메트릭(ascender, descender, capHeight, xHeight)을 활용해 정밀한 베이스라인 정렬이나 커스텀 타이포그래피 레이아웃을 구현할 때 참고값으로 쓴다.

주의사항

  • 여러 번 호출됨: 리렌더·리사이즈마다 다시 불릴 수 있다. 한 번만 처리해야 하는 로직은 ref 가드로 보호한다.
  • numberOfLines와의 상호작용: 잘린 결과가 lines에 반영되므로, 원본 줄 수가 필요하면 제한 없는 측정이 필요하다.
  • 빈 텍스트: 내용이 없으면 lines가 빈 배열일 수 있다.
  • 부수효과 위치: onTextLayout 안에서 무조건 setState를 호출하면 측정→리렌더→재측정 루프에 빠질 수 있으므로, 값이 실제로 바뀔 때만 상태를 갱신하도록 비교 후 업데이트한다.
profile
이력서 https://resume.eunsu.pro

0개의 댓글