본문 바로가기

React-native

[ React Native ] 재사용 가능 팝업 ( reusable popup ) 모달 만들기

0. 참고사항

- 저는 스타일드컴포넌트를 사용하다 보니 이것을 사용하지 않는다면 stylesheet로 스타일을 지정하지 않습니다.

- theme 파일을 따로 만들어서 사용하다 보니 코드 그대로 사용하기 어렵습니다. ( fontsize, color 등 앱에서 공통된 요소들 묶어놓은 파일)

- 모달이다 보니 중복으로 팝업을 뛰울수가 없습니다.

 

 

1.  모달 라이브러리 설치

npm install react-native-modal
cd ios && pod install && cd ..	// ios 셋팅

 

2. 팝업 전체코드

import React, {
  forwardRef,
  useImperativeHandle,
  useState,
} from 'react';
import styled from 'styled-components/native';
import Modal from 'react-native-modal';
import theme from '../theme';
import {useNavigation} from '@react-navigation/native';

//// 스타일드 컴포넌트 //// -------------------------------------
const Modal_Container = styled.View`
  justify-content: center;
  align-items: center;
`;

// 팝업 내용 뷰
const PopUpView = styled.View`
  min-width: 85%;
  background-color: white;
  border-radius: 8px;
  margin: 10%;
  overflow: hidden;
`;
const Modal_ContentView = styled.View`
  height: 180px;
  align-items: center;
  justify-content: center;
`;
const TitleText = styled.Text`
  color: ${theme.colors.fontMain};
  margin: 5% 10% 0%;
  font-size: ${theme.fontsizes.large};
  font-family: ${theme.family.medium};
  text-align: center;
`;
const ContentText = styled.Text`
  color: ${theme.colors.fontGray};
  font-size: ${theme.fontsizes.normal};
  text-align: center;
  padding: 0px 15px;
`;

// 확인 버튼 뷰
const Modal_BottomView = styled.View`
  flex-direction: row;
  height: 50px;
`;
const Modal_OkBtn = styled.TouchableOpacity`
  flex: 1;
  background-color: ${props =>
    props.disabled ? theme.colors.btnGray : theme.colors.main};
  align-items: center;
  justify-content: center;
`;
const Modal_OkBtnText = styled.Text`
  color: white;
  font-family: ${theme.family.medium};
  font-size: ${theme.fontsizes.xlarge};
`;

// 닫기 버튼 뷰
const Btn = styled.TouchableOpacity`
  position: absolute;
  top: 1%;
  right: 1%;
`;
const Icon = styled.Image`
  width: 35px;
  height: 35px;
`;
// --------------------------------------------------------

const Modal_Popup = forwardRef((props, ref) => {
  const [modalVisible, setModalVisible] = useState(false);	// 팝업 보일지 유무
  const [modal_content, setModal_content] = useState(''); // 팝업 내용
  const [btnText, setBtnText] = useState(null);		// 팝업 버튼 내용
  const [data, setData] = useState({});				// 팝업 데이터
  const [clickOk, setClickOk] = useState(false);	// 확인버튼 클릭 유무
  const navigation = useNavigation();

  // 팝업 호출 메서드 
  useImperativeHandle(ref, () => ({
    // 1버튼 팝업
    visible: (content, btnText, getData) => {
      initData();
      content === undefined ? null : setModal_content(content);
      btnText === undefined ? setBtnText('확인') : setBtnText(btnText);
      getData === undefined ? null : setData(getData);
      setModalVisible(true);
    },
  }));
  
  // 팝업 호출할때 초기화 시키기 ( 혹시모르는 변수가 생길수 있으니 만든 부분, 없어도 잘 작동됨)
  const initData = () => {
    setModal_content('');
    setBtnText('확인');
    setData({});
    setClickOk(false);
  };

  return (
    <Modal
      style={{margin: 0, justifyContent: 'center'}}
      onBackdropPress={() => {
        setModalVisible(false);
      }}
      backdropOpacity={0.5}
      animationIn="fadeIn"
      animationOut="fadeOut"
      onModalHide={() => {
      	// 모달이 사라질때 호출되는 함수
        if (clickOk) {
        	// 확인버튼 클릭되었을 때
            // 이벤트를 넣고 싶다면 visible() 호출할때 데이터에 값을 넣어주면 됨
          if (data.clickEvent !== undefined) {
            data.clickEvent();
          }
        }
      }}
      isVisible={modalVisible}>
      <Modal_Container>
        <PopUpView>
          <Modal_ContentView>
            <Btn
              onPress={() => {
                setModalVisible(false);
              }}>
              <Icon source={require('../image/ic_xmark.png')} />
            </Btn>
            <TitleText>{modal_content}</TitleText>
            <ContentText>{content}</ContentText>
            <Content_Input
              show={inputVisible}
              multiline={true}
              textAlignVertical="top"
              placeholderTextColor={theme.colors.fontLightGray}
              placeholder="내용을 입력해주세요."
              onChangeText={text => setInputText(text)}>
              {inputText}
            </Content_Input>
          </Modal_ContentView>

          <Modal_BottomView>
            <Modal_OkBtn
              disabled={inputVisible && inputText === ''}
              onPress={() => {
              	// 확인 버튼 누르면 기본적으로 모달감추기
                setModalVisible(false);
                setClickOk(true);
              }}>
              <Modal_OkBtnText>{btnText}</Modal_OkBtnText>
            </Modal_OkBtn>
          </Modal_BottomView>
        </PopUpView>
      </Modal_Container>
    </Modal>
  );
});
export default Modal_Popup;

 

3. 팝업 사용하기

import React, {useRef} from 'react';
import styled from 'styled-components/native';
import Modal_Popup from '../Component/Modal_Popup';
const Container = styled.SafeAreaView`
  flex: 1;
  background-color: white;
`;
const ContentView = styled.View`
  flex: 1;
  justify-content: center;
  align-items: center;
`;
const Btn = styled.TouchableOpacity`
  padding: 5px 10px;
  border-width: 1px;
  background-color: aliceblue;
`;
const BtnText = styled.Text`
  font-size: 20px;
`;

const Home = () => {
  const popup = useRef();

  const clickBtn = () => {
    popup.current.visible('팝업 내용', '버튼 내용');
  };

  return (
    <Container>
      <ContentView>
        <Btn onPress={clickBtn}>
          <BtnText>{'팝업 호출하기'}</BtnText>
        </Btn>
      </ContentView>
      <Modal_Popup ref={popup} />
    </Container>
  );
};

export default Home;

 

4. 결과