ReactNative

[React Native] PickerSelect 사용하기 (datepicker)

728x90

개요

앱에서 picker는 사용자의 입력값을 개발자가 제시함으로써 입력에 대한 오류를 줄일 수 있는 방법입니다.

저는 개인 프로젝트를 진행하면서 2가지의 PickerSelect가 필요했습니다. 이 블로그에서는 그 중 하나인 datepicker을 modal로 띄우는 라이브러리에 대해 정리하였습니다.

 

1. datepicker

2. picker

 

설치

처음엔 @react-native-community/datetimepicker 를 사용하고자 했는데, modal로 표현하기가 어려워 react-native-modal-datetime-picker를 사용하게되었습니다.

https://github.com/mmazzarolo/react-native-modal-datetime-picker

 

mmazzarolo/react-native-modal-datetime-picker

A React-Native datetime-picker for Android and iOS - mmazzarolo/react-native-modal-datetime-picker

github.com

 

# using npm
npm i react-native-modal-datetime-picker @react-native-community/datetimepicker

# using yarn
yarn add react-native-modal-datetime-picker @react-native-community/datetimepicker

 

프로젝트 상단에서 ios에도 해당 라이브러리를 설치합니다.

cd ios && pod install && cd ../

 

상단에 DateTimePickerModal 을 import 한 후, git 홈페이지의 예제를 추가합니다.

import React, {useState} from 'react'
import { View, Button } from 'react-native'
import DateTimePickerModal from "react-native-modal-datetime-picker";

export default function Home() {
    const [isDatePickerVisible, setDatePickerVisibility] = useState(false);

    const showDatePicker = () => {
        setDatePickerVisibility(true);
    };

    const hideDatePicker = () => {
        setDatePickerVisibility(false);
    };

    const handleConfirm = (date) => {
        console.warn("A date has been picked: ", date);
        hideDatePicker();
    };

    return (
        <View>
            <Button title="Show Date Picker" onPress={showDatePicker} />
            <DateTimePickerModal
                isVisible={isDatePickerVisible}
                mode="date"
                onConfirm={handleConfirm}
                onCancel={hideDatePicker}
            />
        </View>
  );
}

 

프로젝트 터미널에서  아래 명령어를 통해 ios 시뮬레이터를 실행합니다.

react-native run-ios

그러면 아래와 같이 Show Date Picker 를 클릭 했을 때, 위와 같이 정상적으로 실행됨을 알 수있습니다.

TextInput이 존재하고, 이를 클릭하면 DatePicker가 나오기를 원하기 때문에 View태그 안의 항목들을 지우고 아래와 같이 코드를 수정합니다.

<View style={styles.container}>
  <TouchableOpacity onPress={showDatePicker}>
      <TextInput
        pointerEvents="none"
        style={styles.textInput}
        placeholder={placeholder}
        placeholderTextColor="#000000"
        underlineColorAndroid="transparent"
        editable={false}
        value={text}
      />
      <DateTimePickerModal
        headerTextIOS={placeholder}
        isVisible={isDatePickerVisible}
        mode="date"
        onConfirm={handleConfirm}
        onCancel={hideDatePicker}
      />
  </TouchableOpacity>	
</View>	

Textinput을 TouchableOpacity로 감싸 해당 TextInput을 클릭 시 onPress를 통해 showDatePicker함수를 호출할 수 있도록 하였습니다.

위를 실행하면, styles.textInput, text 그리고 placeholder가 없기 때문에 에러가 발생합니다.

 

아래 소스들을 추가 해줍니다.

// 1) 추가
import { View, StyleSheet, TouchableOpacity, TextInput } from 'react-native'

...

export default function Home() {
// 2) 추가
const placeholder = "날짜를 입력해주세요";
const [text, onChangeText] = useState("");

...

}

// 3) 추가
const styles = StyleSheet.create({ 
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: 'white',
    },
    textInput: {
        fontSize: 16,
        color: '#000000',
        height: 50, 
        width: 300, 
        borderColor: '#000000', 
        borderWidth: 1, 
        borderRadius: 12,
        padding: 10
    }
})

 

아래와 같이 TextInput을 클릭 했을 때 DatePickerModal이 잘 적용이됩니다. 하지만, 날짜를 클릭을 해도 TextInput의 값은 변경이 되질 않고 노란색으로 날짜를 띄우는데 몇 줄의 코드를 더 추가하여 작동시켜줍니다.

 

waring에 뜨는 Date 값은 국제표준기구에서 지정한 포맷입니다. ( ISO-8601 )

이 값을 우리가 원하는 yyyy/MM/dd 방식으로 수정하고, textInput의 값을 변경하도록 하겠습니다.

 

import 바로 밑에 아래소스와 같이 fomat과 관련된 함수를 하나 추가합니다. 

Date객체의 prototype에 format이라는 함수를 하나 생성하는 것인데, 이를 통해 Date객체에서 format함수를 사용 할 수 있게됩니다. 

Date.prototype.format = function(f) {
    if (!this.valueOf()) return " ";
 
    var weekName = ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"];
    var d = this;
     
    return f.replace(/(yyyy|yy|MM|dd|E|hh|mm|ss|a\/p)/gi, function($1) {
        switch ($1) {
            case "yyyy": return d.getFullYear();
            case "yy": return (d.getFullYear() % 1000).zf(2);
            case "MM": return (d.getMonth() + 1).zf(2);
            case "dd": return d.getDate().zf(2);
            case "E": return weekName[d.getDay()];
            case "HH": return d.getHours().zf(2);
            case "hh": return ((h = d.getHours() % 12) ? h : 12).zf(2);
            case "mm": return d.getMinutes().zf(2);
            case "ss": return d.getSeconds().zf(2);
            case "a/p": return d.getHours() < 12 ? "오전" : "오후";
            default: return $1;
        }
    });
};
 
String.prototype.string = function(len){var s = '', i = 0; while (i++ < len) { s += this; } return s;};
String.prototype.zf = function(len){return "0".string(len - this.length) + this;};
Number.prototype.zf = function(len){return this.toString().zf(len);};


/* 출처: https://stove99.tistory.com/46 [스토브 훌로구] */

 

이제 format함수를 통해 Date 포맷을 변경해줍니다.

미리 선언해놨던 handleConfirm 함수를 아래와 같이 수정합니다.

const handleConfirm = (date) => {
  console.warn("dateFormat: ", date.format("yyyy/MM/dd"));
  hideDatePicker();
  onChangeText(date.format("yyyy/MM/dd"))
};

이제 제가 원했던 DatePicker대로 동작을 합니다. date.format함수의 경우 '/' 외에도 다양한 포맷으로 사용 할 수 있습니다.

//2011년 09월 11일 오후 03시 45분 42초
console.log(new Date().format("yyyy년 MM월 dd일 a/p hh시 mm분 ss초"));
 
//2011-09-11
console.log(new Date().format("yyyy-MM-dd"));
 
//'11 09.11
console.log(new Date().format("'yy MM.dd"));
 
//2011-09-11 일요일
console.log(new Date().format("yyyy-MM-dd E"));
 
//현재년도 : 2011
console.log("현재년도 : " + new Date().format("yyyy"));


출처: https://stove99.tistory.com/46 [스토브 훌로구]

 

전체 code

import React, {useState} from 'react'
import { View, StyleSheet, TouchableOpacity, TextInput } from 'react-native'
import DateTimePickerModal from "react-native-modal-datetime-picker";

Date.prototype.format = function(f) {
    if (!this.valueOf()) return " ";
 
    var weekName = ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"];
    var d = this;
     
    return f.replace(/(yyyy|yy|MM|dd|E|hh|mm|ss|a\/p)/gi, function($1) {
        switch ($1) {
            case "yyyy": return d.getFullYear();
            case "yy": return (d.getFullYear() % 1000).zf(2);
            case "MM": return (d.getMonth() + 1).zf(2);
            case "dd": return d.getDate().zf(2);
            case "E": return weekName[d.getDay()];
            case "HH": return d.getHours().zf(2);
            case "hh": return ((h = d.getHours() % 12) ? h : 12).zf(2);
            case "mm": return d.getMinutes().zf(2);
            case "ss": return d.getSeconds().zf(2);
            case "a/p": return d.getHours() < 12 ? "오전" : "오후";
            default: return $1;
        }
    });
};
 
String.prototype.string = function(len){var s = '', i = 0; while (i++ < len) { s += this; } return s;};
String.prototype.zf = function(len){return "0".string(len - this.length) + this;};
Number.prototype.zf = function(len){return this.toString().zf(len);};



export default function Home() {
    const placeholder = "날짜를 입력해주세요";

    const [isDatePickerVisible, setDatePickerVisibility] = useState(false);
    const [text, onChangeText] = useState("");
    
    const showDatePicker = () => {
        setDatePickerVisibility(true);
    };

    const hideDatePicker = () => {
        setDatePickerVisibility(false);
    };

    const handleConfirm = (date) => {
        console.warn("dateFormat: ", date.format("yyyy/MM/dd"));
        hideDatePicker();
        onChangeText(date.format("yyyy/MM/dd"))
    };

    return (
        <View style={styles.container}>
            <TouchableOpacity onPress={showDatePicker}>
                <TextInput
                    pointerEvents="none"
                    style={styles.textInput}
                    placeholder={placeholder}
                    placeholderTextColor='#000000'
                    underlineColorAndroid="transparent"
                    editable={false}
                    value={text}
                />
                <DateTimePickerModal
                    headerTextIOS={placeholder}
                    isVisible={isDatePickerVisible}
                    mode="date"
                    onConfirm={handleConfirm}
                    onCancel={hideDatePicker}
                />
            </TouchableOpacity>
        </View>
  );
}

const styles = StyleSheet.create({ 
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: 'white',
    },
    textInput: {
        fontSize: 16,
        color: '#000000',
        height: 50, 
        width: 300, 
        borderColor: '#000000', 
        borderWidth: 1, 
        borderRadius: 12,
        padding: 10
    }
})

 

후기

@react-native-community/datetimepicker을 통해 modal datepicker을 구현하려고 시간을 많이 썼는데, 이미 구현된 라이브러리가 있어 편리하고 사용했었습니다.

date format함수의 경우 prototype에 추가하는데 굉장히 편리하다는 느낌을 받았습니다. 하지만 prototype에 추가하는 행위가 기존에 객체에 존재하는 메서드라고 착각 하여 혼란을 줄 수 있기 때문에 사용은 지양해야한다고 생각합지만.. 그래도 format을 추가하는건 좋아보입니다.

 

반응형