사용하는 이유

컴포넌트 모달의 state를 가지고 있으면 state가 바뀔 때마다 같이 랜더링 된다.

또 별도의 스크린으로 되어 있으면 어디서든 쉽게 접근할 수 있다.

메인 navigation

<NavigationContainer theme={mode === "dark" ? MyDarkTheme : MyTheme}>
  <Root.Navigator
    screenOptions={() => ({
      headerShown: false,
    })}
    **mode="modal"**
  >
    {!!!auth ? (
      <Root.Screen name="NoAuthStacks" component={NoAuthStacks} />
    ) : (
      <>
        <Root.Screen name="BottomTabs" component={BottomTabs} />
        <Root.Screen name="Stacks" component={Stacks} />
      </>
    )}
    **<Root.Screen
      name="ModalStacks"
      component={ModalStacks}
      options={{
        gestureEnabled: false,
        animationEnabled: false,
        cardStyle: { backgroundColor: "transparent" },
        cardOverlayEnabled: true,
      }}
    />**
  </Root.Navigator>
</NavigationContainer>

모달을 pop해주기 위해서 최상단 navigator mode="modal" 로 해준다.

import React from "react";
import { createStackNavigator } from "@react-navigation/stack";
import { AlertScreen } from "@screens/ModalStacks";

const ModalStack = createStackNavigator();

const ModalStacks = () => {
  return (
    <ModalStack.Navigator
      headerMode="none"
      mode="modal"
      screenOptions={{
        **headerShown: false,
        cardStyle: { backgroundColor: "#00000060" },
        cardOverlayEnabled: true,
        animationEnabled: false,
        gestureEnabled: false,**
      }}
    >
      <ModalStack.Screen name="AlertScreen" component={AlertScreen} />
    </ModalStack.Navigator>
  );
};

export default ModalStacks;
import { useNavigation, useRoute } from "@react-navigation/native";
import { ModaRouteProps } from "@types";
import React, { useEffect, useRef } from "react";
import { View, Button, Text, Animated, Easing } from "react-native";

const AlertScreen = () => {
  const {
    params: { title, content },
  } = useRoute();
  const nav = useNavigation();

  const opacity = useRef(new Animated.Value(0)).current;
  const translateY = opacity.interpolate({
    inputRange: [0, 1],
    outputRange: [500, 0],
  });

  useEffect(() => {
		Animated.timing(opacity, {
      toValue: 1,
      duration: 150,
      useNativeDriver: true,
      easing: Easing.inOut(Easing.ease),
    }).start();
  }, []);

  const onPress = () => {
    Animated.timing(opacity, {
      toValue: 0,
      duration: 100,
      useNativeDriver: true,
      easing: Easing.inOut(Easing.ease),
    }).start(nav.goBack);
  };

  return (
    <View style={{ flex: 1, justifyContent: "center" }}>
      <Animated.View
        style={{
          marginHorizontal: 30,
          opacity,
          transform: [{ translateY }],
        }}
      >
        <Button
          title="확인"
          onPress={onPress}
          weight="medium"
          height={48}
        />
      </Animated.View>
    </View>
  );
};

export default AlertScreen;

참고

[React Native] Android - 모달을 띄울 때 화면이 반쯤 넘어가는 문제 해결