๐Ÿ“š[Rใ†N] Modal ์ œ๋Œ€๋กœ ์“ฐ์ž !

๋ฐ•์• ๋ฆฌยท2026๋…„ 1์›” 22์ผ
post-thumbnail

๐Ÿ”Š react-native-modal ๊ธฐ๋Šฅ์„ ์•Œ์•„๋ณด๊ธฐ!๐Ÿช„


๊ฐœ๋ฐœํ•˜๋‹ค ๋ณด๋ฉด โ€œ๋ชจ๋‹ฌโ€์€ ๊ฑฐ์˜ ํ•„์ˆ˜์ธ๋ฐ์š”, React Native ๊ธฐ๋ณธ Modal๋งŒ์œผ๋กœ๋„ ๊ตฌํ˜„์€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒโ€ฆ
  • ๋ฐฑ๋“œ๋กญ(๋ฐ”๊นฅ ์˜์—ญ) ๋ˆŒ๋Ÿฌ์„œ ๋‹ซ๊ธฐ
  • ์Šค์™€์ดํ”„ํ•ด์„œ ๋‹ซ๊ธฐ(์ œ์Šค์ฒ˜)
  • ๋” ๋ถ€๋“œ๋Ÿฌ์šด ์• ๋‹ˆ๋ฉ”์ด์…˜ / ๋ฐฑ๋“œ๋กญ ์• ๋‹ˆ๋ฉ”์ด์…˜
  • ์œ„์น˜ ์กฐ์ ˆ / ํ‚ค๋ณด๋“œ ๋Œ€์‘

๊ฐ™์€ ์ž์ฃผ ์“ฐ๋Š” UX๋ฅผ ๋งŒ๋“ค๋ ค๋ฉด ์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด์ง€๊ธฐ ์‰ฌ์›Œ์š”.


๊ทธ๋ž˜์„œ ์˜ค๋Š˜์€ react-native-modal์ด ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด์„œ ์ •๋ฆฌํ•ด๋ณด๋ คํ•ฉ๋‹ˆ๋‹ค!


๋จผ์ €, RN ๊ณต์‹ Modal ์˜ˆ์‹œ (๊ธฐ๋ณธ Modal)

React Native ๊ณต์‹ ๋ฌธ์„œ์— ์žˆ๋Š” ์˜ˆ์‹œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ์ด๋Ÿฐ ๋А๋‚Œ์ด์ฃ .

  • animationType="slide" ๋กœ ๋“ฑ์žฅ ๋ฐฉ์‹ ์ œ์–ด
  • transparent ๋กœ ๋ฐฐ๊ฒฝ ํˆฌ๋ช… ์ฒ˜๋ฆฌ
  • visible ์ƒํƒœ๋กœ ์—ด๊ณ  ๋‹ซ๊ธฐ

(์ด ๋ฐฉ์‹๋„ ์ถฉ๋ถ„ํžˆ ์ข‹์ง€๋งŒ, ๋””ํ…Œ์ผํ•œ UX๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ ์ฝ”๋“œ๊ฐ€ ์ ์  ๊ธธ์–ด์ง‘๋‹ˆ๋‹ค.)


react-native-modal์„ ์“ฐ๋Š” ์ด์œ 

react-native-modal์€ RN ๊ธฐ๋ณธ Modal์„ ๊ฐ์‹ธ์„œ ๋ชจ๋‹ฌ UX๋ฅผ ์‰ฝ๊ฒŒ ํ™•์žฅํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ˆ์š”.

ํŠนํžˆ ์ด๋Ÿฐ ๊ธฐ๋Šฅ์ด ํŽธํ•ฉ๋‹ˆ๋‹ค.

  • โœ… ๋ฐฑ๋“œ๋กญ ํƒญ์œผ๋กœ ๋‹ซ๊ธฐ (onBackdropPress)
  • โœ… ์Šค์™€์ดํ”„ ๋‹ซ๊ธฐ (swipeDirection, onSwipeComplete)
  • โœ… ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ข…๋ฅ˜ ์„ ํƒ (animationIn, animationOut)
  • โœ… ๋ฐฑ๋“œ๋กญ ์• ๋‹ˆ๋ฉ”์ด์…˜/ํˆฌ๋ช…๋„ (backdropOpacity)
  • โœ… ํ‚ค๋ณด๋“œ ์˜ฌ๋ผ์˜ฌ ๋•Œ ๋ฐ€๋ ค๋‚˜๊ฒŒ ์ฒ˜๋ฆฌ (avoidKeyboard)
  • โœ… ์•ˆ์ „ํ•˜๊ฒŒ ๋‹ซํž˜ ์ฒ˜๋ฆฌ ์ฝœ๋ฐฑ (onModalHide)

์„ค์น˜

npm i react-native-modal
# ๋˜๋Š”
yarn add react-native-modal

์šฐ๋ฆฌ๊ฐ€ ๊ตฌํ˜„ํ•  โ€œ๊ผญ ํ•„์š”ํ•œ ๋ชจ๋‹ฌโ€ ๊ธฐ๋Šฅ

์˜ค๋Š˜ ๋งŒ๋“ค ๋ชจ๋‹ฌ ์ŠคํŽ™์€ ๋”ฑ ์ด ์ •๋„๋งŒ!

  • ์—ด๊ธฐ / ๋‹ซ๊ธฐ (state)
  • ๋ฐฑ๋“œ๋กญ(๋ฐฐ๊ฒฝ) ๋ˆŒ๋Ÿฌ์„œ ๋‹ซ๊ธฐ
  • ์•ˆ๋“œ๋กœ์ด๋“œ ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ์œผ๋กœ ๋‹ซ๊ธฐ
  • ์•„๋ž˜๋กœ ์Šค์™€์ดํ”„ํ•ด์„œ ๋‹ซ๊ธฐ (์ œ์Šค์ฒ˜)
  • ๋ถ€๋“œ๋Ÿฌ์šด ๋“ฑ์žฅ/ํ‡ด์žฅ ์• ๋‹ˆ๋ฉ”์ด์…˜

โœ… ์ตœ์†Œ ์ฝ”๋“œ๋กœ ์‹ค์ „ ๋ชจ๋‹ฌ ๋งŒ๋“ค๊ธฐ (BackDrop + Swipe)

์•„๋ž˜ ์ฝ”๋“œ๋Š” โ€œํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒโ€ ๊ณจ๋ผ์„œ ๋„ฃ์€, ๊ฐ€์žฅ ์‹ค์ „ํ˜• ๊ธฐ๋ณธ ํ…œํ”Œ๋ฆฟ์ด์—์š”.

๐Ÿ‘‰ ์ฝ”๋“œ ๋ณด๊ธฐ
import React, {useState} from 'react';
import {Alert, Modal, StyleSheet, Text, Pressable, View} from 'react-native';
import {SafeAreaView, SafeAreaProvider} from 'react-native-safe-area-context';

const App = () => {
  const [modalVisible, setModalVisible] = useState(false);

  return (
    <SafeAreaProvider>
      <SafeAreaView style={styles.centeredView}>
        <Modal
          animationType="slide"
          transparent={true}
          visible={modalVisible}
          onRequestClose={() => {
            Alert.alert('Modal has been closed.');
            setModalVisible(!modalVisible);
          }}>
          <View style={styles.centeredView}>
            <View style={styles.modalView}>
              <Text style={styles.modalText}>Hello World!</Text>
              <Pressable
                style={[styles.button, styles.buttonClose]}
                onPress={() => setModalVisible(!modalVisible)}>
                <Text style={styles.textStyle}>Hide Modal</Text>
              </Pressable>
            </View>
          </View>
        </Modal>

        <Pressable
          style={[styles.button, styles.buttonOpen]}
          onPress={() => setModalVisible(true)}>
          <Text style={styles.textStyle}>Show Modal</Text>
        </Pressable>
      </SafeAreaView>
    </SafeAreaProvider>
  );
};

const styles = StyleSheet.create({
  centeredView: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  modalView: {
    margin: 20,
    backgroundColor: 'white',
    borderRadius: 20,
    padding: 35,
    alignItems: 'center',
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.25,
    shadowRadius: 4,
    elevation: 5,
  },
  button: {
    borderRadius: 20,
    padding: 10,
    elevation: 2,
  },
  buttonOpen: { backgroundColor: '#F194FF' },
  buttonClose: { backgroundColor: '#2196F3' },
  textStyle: {
    color: 'white',
    fontWeight: 'bold',
    textAlign: 'center',
  },
  modalText: {
    marginBottom: 15,
    textAlign: 'center',
  },
});

export default App;

๐Ÿงฉ Modal ์˜ต์…˜ ์ •๋ฆฌ (React Native Modal + react-native-modal)

์•„๋ž˜๋Š” โ€œ์ด ๊ธ€์˜ ๋ชฉ์ (๊ฐ€๋ณ๊ฒŒ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒ)โ€์— ๋งž์ถฐ, ์ž์ฃผ ์“ฐ๋Š” ์˜ต์…˜๋งŒ ํ”Œ๋žซํผ๋ณ„๋กœ ์ •๋ฆฌํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.


โœ… ๊ณตํ†ต (iOS / Android)

๐Ÿ”น React Native Modal

1) animationType

๋ชจ๋‹ฌ์ด ์–ด๋–ค ์• ๋‹ˆ๋ฉ”์ด์…˜์œผ๋กœ ๋“ฑ์žฅํ• ์ง€ ์ œ์–ด

<Modal animationType="slide" />
  • slide โ†’ ์•„๋ž˜์—์„œ ์œ„๋กœ ๋“ฑ์žฅ
  • fade โ†’ ์„œ์„œํžˆ ๋‚˜ํƒ€๋‚จ
  • none โ†’ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์—†์Œ

2) transparent

๋ชจ๋‹ฌ ๋ฐฐ๊ฒฝ ํˆฌ๋ช… ์—ฌ๋ถ€

<Modal transparent />
  • true โ†’ ๋ฐฐ๊ฒฝ ํˆฌ๋ช… (์ปค์Šคํ…€ ๋ฐฑ๋“œ๋กญ ํ•„์š”)
  • false โ†’ ๊ธฐ๋ณธ ํฐ์ƒ‰ ๋ฐฐ๊ฒฝ

3) onRequestClose

๋ชจ๋‹ฌ์ด ๋‹ซํžˆ๋ ค๊ณ  ํ•  ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ์ฝœ๋ฐฑ

<Modal onRequestClose={() => setVisible(false)} />
  • Android: ํ•˜๋“œ์›จ์–ด ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ
  • iOS: ๋“œ๋ž˜๊ทธ ์ œ์Šค์ฒ˜
  • Android์—์„œ๋Š” ํ•„์ˆ˜ ๊ตฌํ˜„ ๊ถŒ์žฅ

4) onShow

๋ชจ๋‹ฌ์ด ํ™”๋ฉด์— ํ‘œ์‹œ๋œ ์งํ›„ ํ˜ธ์ถœ

<Modal onShow={() => console.log('opened')} />
  • ๋กœ๊น…, analytics, focus ์ฒ˜๋ฆฌ ๋“ฑ์— ํ™œ์šฉ

๐Ÿ”น react-native-modal

5) isVisible

๋ชจ๋‹ฌ ์—ด๋ฆผ / ๋‹ซํž˜ ์ƒํƒœ

<Modal isVisible={visible} />

6) onBackdropPress

๋ชจ๋‹ฌ ๋ฐ”๊นฅ ์˜์—ญ(๋ฐฑ๋“œ๋กญ)์„ ๋ˆŒ๋Ÿฌ ๋‹ซ๊ธฐ

<Modal onBackdropPress={() => setVisible(false)} />

7) backdropOpacity

๋ฐฑ๋“œ๋กญ ํˆฌ๋ช…๋„(์–ด๋‘์šด ์ •๋„)

<Modal backdropOpacity={0.4} />

8) animationIn / animationOut

๋“ฑ์žฅ / ํ‡ด์žฅ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์„ค์ •

<Modal animationIn="slideInUp" animationOut="slideOutDown" />

9) useNativeDriver

์• ๋‹ˆ๋ฉ”์ด์…˜ ์„ฑ๋Šฅ ์ตœ์ ํ™” ์˜ต์…˜

<Modal useNativeDriver />

๐ŸŽ iOS ์ „์šฉ

๐Ÿ”น React Native Modal

10) onDismiss

๋ชจ๋‹ฌ์ด ์™„์ „ํžˆ ๋‹ซํžŒ ํ›„ ํ˜ธ์ถœ

<Modal onDismiss={() => console.log('closed')} />
  • ๋‹ซํž˜ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ข…๋ฃŒ ํ›„ ์‹คํ–‰

11) onOrientationChange

๋ชจ๋‹ฌ์ด ๋–  ์žˆ๋Š” ๋™์•ˆ ํ™”๋ฉด ๋ฐฉํ–ฅ ๋ณ€๊ฒฝ ๊ฐ์ง€

<Modal
  onOrientationChange={(event) => {
    console.log(event.orientation);
  }}
/>
  • "portrait" โ†’ ์„ธ๋กœ
  • "landscape" โ†’ ๊ฐ€๋กœ

12) allowSwipeDismissal

์•„๋ž˜๋กœ ์Šค์™€์ดํ”„ํ•ด์„œ ๋ชจ๋‹ฌ ๋‹ซ๊ธฐ ํ—ˆ์šฉ ์—ฌ๋ถ€

<Modal allowSwipeDismissal />
  • iOS ์ „์šฉ
  • ๊ธฐ๋ณธ Modal์—์„œ๋งŒ ์ œ๊ณต

๐Ÿ”น react-native-modal

13) swipeDirection

์Šค์™€์ดํ”„๋กœ ๋ชจ๋‹ฌ ๋‹ซ๊ธฐ (์ œ์Šค์ฒ˜)

<Modal swipeDirection="down" />
  • "down" | "up" | "left" | "right"
  • ๋ฐฐ์—ด๋„ ๊ฐ€๋Šฅ: ["down", "left"]

14) onSwipeComplete

์Šค์™€์ดํ”„๊ฐ€ ์™„๋ฃŒ๋์„ ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ์ฝœ๋ฐฑ

<Modal onSwipeComplete={() => setVisible(false)} />

๐Ÿค– Android ์ „์šฉ

๐Ÿ”น React Native Modal

15) hardwareAccelerated

๋ชจ๋‹ฌ์„ GPU ๋ Œ๋”๋ง์œผ๋กœ ๊ฐ•์ œ

<Modal hardwareAccelerated />
  • ํˆฌ๋ช… View + ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹œ ๋ฐœ์ƒํ•˜๋Š”

    • ๊ฒ€์€ ํ™”๋ฉด
    • ๊นœ๋นก์ž„
    • ๋ Œ๋”๋ง ์˜ค๋ฅ˜
      ๋ฐฉ์ง€ ๋ชฉ์ 
  • Android ์ „์šฉ (iOS ๋ฌด์‹œ)


16) statusBarTranslucent

๋ชจ๋‹ฌ์ด ์ƒํƒœ๋ฐ” ์˜์—ญ ์•„๋ž˜๊นŒ์ง€ ํ™•์žฅ๋ ์ง€ ์—ฌ๋ถ€

<Modal statusBarTranslucent />
  • true โ†’ ์ƒํƒœ๋ฐ”๊นŒ์ง€ ๋ฎ์Œ
  • false โ†’ ์ƒํƒœ๋ฐ” ์•„๋ž˜๋ถ€ํ„ฐ ํ‘œ์‹œ
  • Android 10+ ์ด์ƒ ๊ถŒ์žฅ

๋งˆ๋ฌด๋ฆฌ

React Native ๊ธฐ๋ณธ Modal๋งŒ์œผ๋กœ๋„ ๊ตฌํ˜„์€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ,
๋ฐฑ๋“œ๋กญ ํƒญ / ์Šค์™€์ดํ”„ ๋‹ซ๊ธฐ / ์ž์—ฐ์Šค๋Ÿฌ์šด ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ฐ™์€ UX๋ฅผ ๊ตฌํ˜„ํ•˜๋ ค๋ฉด
์ถ”๊ฐ€ ๊ตฌํ˜„์ด ๋งŽ์ด ํ•„์š”ํ•ด์š”.

react-native-modal์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒ ๊ณจ๋ผ
๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์‹ค์ „ ๋ชจ๋‹ฌ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

+๋’ค ํฌ์ŠคํŠธ์—์„œ ๋”์šฑ ๋‹ค์ฑ„๋กœ์šด ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฐ€๋ณ๊ฒŒ modal์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฒ•๋„ ์ฝ์–ด๋ณด์„ธ์š” ! ๐Ÿ˜Š


---


0๊ฐœ์˜ ๋Œ“๊ธ€