My Boundary As Much As I Experienced

RN) 바텀네비게이션에 바텀시트가 나오게 하는 버튼 만들기(Tab.Navigator) 본문

FrontEnd/React Native

RN) 바텀네비게이션에 바텀시트가 나오게 하는 버튼 만들기(Tab.Navigator)

Bumang 2024. 9. 2. 12:20

분명 네비게이션 버튼인데 특이한 동작이 나오는 커스텀 버튼들이 있다?!

바텀네비게이션 버튼 중에 일반적인 페이지가 아니라 모달이 나오게 하는 페이지들이 존재한다.

 

 

각설하고 이걸 어떻게 구현하는가?

1. 바텀탭 네비게이터에 새로운 페이지 추가

별거 없다. 새로운 Screen컴포넌트를 네비게이터에 일단 추가한다.

ToAddNewDiary라는 컴포넌트를 추가했다.

  return (
    <BottomTab.Navigator
      initialRouteName="Home"
    >
      <BottomTab.Screen // 일반적인 Screen 설정
        name="Home"
        component={Home} // Home스크린(페이지) 컴포넌트를 반환한다.
        options={{
          tabBarLabel: "홈",
          header: () => <CustomHeader type="HOME" />,
        }}
      />
      <BottomTab.Screen // 페이지 추가!
        name="ToAddNewDiary"
      />
      // ...
    </BottomTab.Navigator>
  );
};

 

 

2. Null을 반환하는 컴포넌트를 생성하고 만든 페이지에 준다.

우리가 만드는건 실제 탭전환을 일으키지 않는다. 탭이 전환되는게 아니라

원래 있던 탭에 그대로 있으면서 그 위로 바텀 모달 형식의 페이지가 나와야 하는 것이다.

이를 위해 눌러도 탭전환이 일어나지 않도록 null을 반환하는 컴포넌트를 만든다.

const NullComponent = () => null;

 

그래서 아래처럼 Screen에 제공한다.

      <BottomTab.Screen
        name="ToAddNewDiary"
        component={NullComponent} // '() => null'인 컴포넌트이다.
        options={{
          tabBarLabel: "글쓰기",
        }}
      />

 

 

3. stack에 새로운 페이지를 추가하는 탭바 버튼을 커스텀 추가한다.

스크린의 options에 tabBarButton 속성을 추가한다.

이 속성은 콜백함수를 제공받을 수 있다.

이 콜백함수는 탭바 버튼으로서의 속성들이 들어있는 props를 패러미터로 받는다.

이걸 커스텀 탭바 버튼에 넣으면 된다.

        options={{
          tabBarLabel: "글쓰기",
          tabBarButton: (props) => ( // 원하는 페이지를 stack에 쌓이게 하는 버튼이다.
            <CustomTabBarButton
              {...props}
              onPress={() => addNewDiaryWithAuth(navigation)}
            />
          ),
        }}

 

참고로 탭바 버튼은 아래처럼 생겼다. 플러스아이콘 하나있는 버튼이다.

요녀석

const CustomTabBarButton = ({ onPress }: CustomTabProps) => {
  return (
    <Button onPress={onPress} style={styles.container}>
      <PlusIcon size={24} />
    </Button>
  );
};

 

 

전체 코드로 보면 이렇다.

const NullComponent = () => null;

const BottomTabNavigation = ({
  navigation,
}: {
  navigation: TotalNavigationProp;
}) => {
  return (
    <BottomTab.Navigator
      initialRouteName="Home"
    >
      <BottomTab.Screen // 일반적인 Screen 설정
        name="Home"
        component={Home} // Home스크린(페이지) 컴포넌트를 반환한다.
        options={{
          tabBarLabel: "홈",
          header: () => <CustomHeader type="HOME" />,
        }}
      />
      <BottomTab.Screen
        name="ToAddNewDiary"
        component={NullComponent} // '() => null'인 컴포넌트이다.
        options={{
          tabBarLabel: "글쓰기",
          tabBarButton: (props) => ( // 원하는 페이지를 stack에 쌓이게 하는 버튼이다.
            <CustomTabBarButton
              {...props}
              onPress={() => addNewDiaryWithAuth(navigation)}
            />
          ),
        }}
      />
      // ...
    </BottomTab.Navigator>
  );
};

 

 

ps. 약간의 시행착오: Tab.Screen은 인라인 방식으로 컴포넌트를 받을 수 없다.

처음엔 아래처럼 null을 반환하는 콜백을 인라인으로 제공했는데,

계속 재렌더 될때마다 () => null이 재생성된다?는 에러가 떴었다.

component={() => null}

 

변수에 할당된 고정된 메모리 참조가 있는 값이어야지만 된다는 것 같다.

빨간 화면이 뜨면서 앱이 죽진 않지만 바텀탭을 터치할 때마다 warning이 뜨길래

const NullComponent = () => null;

 

요넘으로 바꿔줬다.