[React Native] 첫 기여 회고 🥳 (Animated.FlatList)

Huckleberry·2023년 3월 1일
30

react-native

목록 보기
2/2
post-thumbnail

결과물

pull-request

문제점

react native 에서 Animated FlatList 를 활용한 컴포넌트를 개발하다가 typescript 에서 이상한 점을 발견했다.

generic T 에 대한 아이템을 렌더링하는 FlatList 의 ref 를 사용하는 custom-hook 을 만들고 있었는데

const useAnimatedFlatListRef = <T>() => {
  const ref = useRef<Animated.FlatList<T> | null>(null);

  const refCallback = useCallback((_ref: Animated.FlatList<T>) => {
    ref.current = _ref;
  }, []);

  return {
    ref,
    refCallback,
  };
};

export default useAnimatedFlatListRef;

아래와 같이 scrollToIndex 라는 프로퍼티가 없다는 에러가 뜨는 상황이였다.
반면, 실제 런타임에는 scrollToIndex, scrollToItem 등 모든 FlatList 의 메서드가 문제없이 동작하는 상황이고 ts 의 도움만 못 받는 상황이였다.

해결과정

react native 패키지를 보면 Animated.FlatListFlatList 를 확장한 컴포넌트인데

export type AnimatedProps<T> = {
        [key in keyof T]: key extends NonAnimatedProps
            ? key extends 'ref'
                ? TAugmentRef<T[key]>
                : T[key]
            : WithAnimatedValue<T[key]>;
    };

AnimatedProps 라는 유틸 타입을 통해서 style 등에서 Animated API 를 사용하는 interpolation 등의 스타일을 허용 하도록 하는데 이때 scrollToIndex 등의 ref 를 통해서 접근 가능한 method 가 없는게 이상하단 생각이 들었다.

해결과정: 1트

FlatList.d.ts 를 보면

export class FlatList<ItemT = any> extends React.Component<
  FlatListProps<ItemT>
> {
  /**
   * Scrolls to the end of the content. May be janky without `getItemLayout` prop.
   */
  scrollToEnd: (params?: {animated?: boolean | null | undefined}) => void;
  // 생략

이렇게 정의 되어 있고

Animated.d.ts

export class FlatList<ItemT = any> extends React.Component<
    AnimatedProps<FlatListProps<ItemT>>
  > {} // << 여기가 비어 있는게 문제 

이렇게 정의 되어 있었는데 이때 {} 로 scrollTo~ 관련 정의가 누락 되어 있는게 문제였다.

그런데 FlatList 에 정의된 메서드들을 재활용하려 해도

interface FlatListMethods<T> {
   scrollToEnd: (params?: {animated?: boolean | null | undefined}) => void;
}

// 오류, 이런 문법은 없음
class FlatList<ItemT = any> extends React.Component<
    AnimatedProps<FlatListProps<ItemT>>
  > FlatListMethods<T>

이러한 문법은 동작하지 않는 문법이였다. 그래서 코드를 재활용할 수 있는 방법이 없나..?
라는 생각이 들었고 너무 무지성으로 그냥 그대로 복사해서 pr 을 우선 올려보았다.

지금 생각해보면 더 고민 해봤어야 했는데 이때 얼른 수정해보고 싶단 생각에 마음이 너무 흥분되고 급했던거 같다.

결국, 리뷰어로 부터

Can we factor this to reuse the imperative methods already defined for VirtualizedList, instead of duplicating this?

위와 같은 어느정도 예상 가능했던 리뷰를 받았고 다시 코드를 재활용할 수 있는 방법에 대해 고민 해봤다.

해결과정: 2트

타입스크립트 class 에서 사용하는 extends 는 어떠한 인터페이스를 확장한 타입이다 라는 문법으로 정의하는데 이때 React.Component 를 extends 를 확장하는게 아니라

Animated.FlatListFlatList 가 공유하는 공통 타입으로 만들어서 해당 타입을 확장하도록 만들면 되지 않을까? 라는 생각이 들었다.

타입스크립트 추상 클래스 abstract class 를 사용하면 실제 구현부 없이 추상 메서드에 대한 인터페이스를 정의할 수 있는데

앗싸 ~ 이거다..!! 🤩 (두근..)

라는 생각이 들었다.

그래서 아래와 같이 FlatListComponent 라는 React.Component 를 확장하는 추상 클래스를 만들었고

// FlatList.d.ts
export abstract class FlatListComponent<
  ItemT,
  Props,
> extends React.Component<Props> {
  /**
   * Scrolls to the end of the content. May be janky without `getItemLayout` prop.
   */
  scrollToEnd: (params?: {animated?: boolean | null | undefined}) => void;
  // 생략
}

// FlatList.d.ts
export class FlatList<ItemT = any> extends FlatListComponent<
  ItemT,
  FlatListProps<ItemT>
> {}

// Animated.d.ts
export namespace Animated {
   export class FlatList<ItemT = any> extends FlatListComponent<
    ItemT,
    AnimatedProps<FlatListProps<ItemT>>
  > {}
}

Animated.FlatList, FlatList 모두 FlatListComponent 를 확장하도록 리팩토링 하였다.

역시 방법이 없는건 아니였다!

그동안 몇개의 오픈소스에 오류를 찾아서 기여한적은 있지만

react native 정도의 거대한 오픈소스에 기여는 처음이였고,
그것도 가장 좋아하는 FlatList 에 contribution 했다는 사실이 너무 뿌듯하고 행복했다.

사실 처음 들었던 걱정은

난 아직 주니어 개발자인데 내가 기여를 할 수 있을까? 이슈만 올려두고 누가 수정 해주길 기다려야 하나..?

라는 생각이 들었지만

코드는 주니어가 작성하던 시니어나 작성하던 똑같이 동작한다. 그냥 해보자. 잘 안되어 봤자 close 되고 끝 아니겠나

로 마음을 고쳐 먹고 해봤던거 같다.

페이스북 측 리뷰어분들이 미국시간대라 주로 새벽에 리뷰를 달아주셨는데 빨리 빨리 확인 하려고 하다보니 몇일 잠도 설쳤던거 같다.

이번엔 타입관련 수정이였지만 분명 언젠간 내부 로직 수정에도 기여할 수 있는 개발자로 성장하고 싶다 🙇🏻‍♂️.

화이팅~!

6개의 댓글

comment-user-thumbnail
2023년 3월 1일

으오아!! 멋진 경험이네요~~ 거대 오픈소스 커뮤니티에 기여라니ㅋㅋ 이런 문화를 볼때마다 개발자라고 하는 직업을 가지고 있는 것에 대해 자부심이 생기는 것 같아요~ 좋은 경험 공유 감사합니다 :)

1개의 답글
comment-user-thumbnail
2023년 3월 2일

레전도리

1개의 답글
comment-user-thumbnail
2023년 3월 2일

오 ㅎㅎ 행동도 멋지고 이렇게 글 써서 공유해주신 것 까지 너무 멋있고 자극되네요 !! 최고 감사합니다 :D

1개의 답글