[React-native] onLayout으로 위치값 가져오기 / 활용

HongDuHyeon·2024년 9월 23일
1
post-thumbnail
유난한 도전

💡 왜 해?

프로덕트를 만들다보면 간혹 새로운 피쳐를 만들고 그 화면에서 추가된 기능을 특별히 보여줘야한다거나 그 화면에서 온보딩을 해야하는 상황이 있다. 그때 내가 보여주고 싶은 요소가 하이라이팅 될 수 있도록 다른 요소들은 rgba값의 알파값을 조절해 어떤 것을 더 보여줄지 만들어 볼 수 있다 !

💡 뭐가 필요해?

첫번째로 React-native에선 모든 코어 컴포넌트에 onLayout 이벤트 속성을 제공한다.

두번째로 onLayout의 Type use인데 이건 react-native에서 제공해주고 있다

import { LayoutChangeEvent } from 'react-native';

💡 어떻게 써?

우선 간단하게 사용하는 법을 알아보자.

<Button
	onPress={() => handleClickToolTip()}
	onLayout={(e) => {
  		const { x, y, width, height } = e.nativeEvent.layout;
		setButtonX(x + width / 2);
		setButtonY(height - PADDING * 2);
	}}
/>

위와 같은 간단한 Button을 만드는 예제가 있다고 가정하면 onLayout의 e에서 x, y, width, height의 값을 받아올 수 있고 내가 원하는 상황에 맞게 값을 더하거나 곱하거나 나눠서 커스텀해서 쓸 수 있다.

이때 x, y, width, height가 뭘 뜻하는지의 대한 설명은 생략 !

💡 어떻게 잘 써?

심화과정 on.

하나의 onLayout을 사용해서 여러개의 값을 가져오고 싶거나 코드의 반복을 줄이고 싶을 수도 있을 겁니다 ! (물론 그런 상황이 아니더라도... 뭐..)

그럴 떈 React.RefObjectMeasurePayload를 사용할 수 있습니다.

React.RefObject란 ?

React에서 특정 DOM 요소 또는 클래스 컴포넌트 인스턴스에 접근하기 위해 사용하는 참조 객체입니다.
예를 들어 React-native에선 View, TouchableOpacity, TextInput 등등 이런 요소들에 속합니다.

MeasurePayload란 ?

MeasurePayload는 따로 타입을 설정해 놓은 것입니다.

export type MeasurePayload = {
  x: number;
  y: number;
  width: number;
  height: number;
  pageX: number;
  pageY: number;
};

왜냐 ?
앞으로 ref.current.measure()에서의 리턴 값을 타입으로 적용해놔서 리턴 되는 데이터의 타입을 지정해놓은 겁니다

리턴 되는 타입

export type MeasureOnSuccessCallback = (
  x: number,
  y: number,
  width: number,
  height: number,
  pageX: number,
  pageY: number,
) => void;

벌써 복잡합니다 좀만 더 정신 차리세요 !

자 위와 같이 간단한 개념 설명은 끝났으니 활용되는 예시로 넘어가봅시다

활용 예시

먼저 내가 사용해야하는 View가 있다고 가정해봅시다.

const viewRef = useRef<View>(null);

<View
	ref={viewRef}
/>

그리고 함수를 하나 준비 해줄겁니다.

const measureRef = useCallback(
    (ref: React.RefObject<View>): Promise<MeasurePayload | null> =>
      new Promise((resolve) => {
        if (!ref.current) {
          resolve(null);
        } else {
          ref.current.measure((x, y, width, height, pageX, pageY) => {
            resolve({ x, y, width, height, pageX, pageY });
          });
        }
      }),
    [],
  );

만약 View가 아닌 다른 요소를 넣고 싶다면

View | TouchableOpacity | TextInput

이렇게 넣으시면 됩니다 ㅎㅎ

이 함수를 해석 해보자면
1. 특정 컴포넌트의 ref를 매개변수로 받는다.
2. Promise로 반환한다.
3. measure로 값을 받아 resolve의 형태로 반환한다.

크게 이렇게 3가지로 볼 수 있습니다.

그래서 다른 점이 뭔데 ?

이벤트 기반

일반적으로 그냥 onLayout으로 작업할 경우엔 레이아웃이 변화할 때마다 자동으로 호출이 됩니다. 처음 렌더링 되거나 화면 크기 조정과 같은 이벤트가 있다면 호출이 됩니다.

추가로 렌더링 시점에 자동으로 호출되기 때문에 한 번의 렌더링 후 레이아웃 정보가 필요할 때는 편리합니다. 추가적으로 상태 관리와 결합해도 문제가 없습니다.

비동기 기반

measureRef로 작업을 하게 되면 특정 시점에 measure()를 호출해 레이아웃의 값을 가져올 수 있습니다. 예를 들어 버튼 클릭시, 특정 액션 후 레이아웃을 측정하는데에 있어서 더 유리합니다

추가로 특정 시점에 레이아웃 정보를 수동으로 요청할 수 있습니다. 이는 onLayout처럼 자동으로 호출되지 않고, 필요할 때만 호출되므로 더욱 제어가 가능합니다. 컴포넌트가 이미 렌더링된 후, 동적으로 다른 로직에 따라 레이아웃을 측정해야 할 때 적합합니다.

이로써 특정 시점에 내가 원하는 컴포넌트의 값들을 받아올 수 있게 되었습니다.
처음엔 생소한 방식이었지만 사용하면 사용할수록 더 많은 걸 해볼 수 있으니 react-native로 개발하시는 분들이 있다면 꼭 한번 사용해보시길 ㅎㅎ

profile
마음이 시키는 프론트엔드.. RN과 IOS를 곁들인..

0개의 댓글