Introduction:
Hello everyone! While working on Cada by Paprika Data Lab Inc., we needed to add date of birth to the user information object. As of April 2022, there is no perfect (simple to use and customizable) library for available for react-native date-time picker, so it took me a long time to figure out how to use the
@react-native-community/datetimepicker
.The method to use it differs for iOS and Android - that means, the code that will work on iOS won’t work on Android.
Â
Note check the versions:
"react-native": "0.64.3",
"expo": "~44.0.0",
"react-native-gesture-handler": "^2.4.0",
"react-native-reanimated": "2.3.1",
"@react-native-community/datetimepicker": "^6.1.2",
"@gorhom/bottom-sheet": "^4",
Let’s start with how it would look on iOS (play the video below)
Here’s how it would look on Android devices (play the video below)
How to: Creating the above component:
Step 1: Installing the required packages
For DateTimepicker:
yarn add @react-native-community/datetimepicker
Usage:
import DateTimePicker from '@react-native-community/datetimepicker';
For Bottomsheet (the popup - it’s kinda necessary for iOS):
install dependencies:
yarn add react-native-reanimated react-native-gesture-handler
yarn add @gorhom/bottom-sheet@^4
make sure to add this to babel.config.js
plugins: ['react-native-reanimated/plugin'],
so your
babel.config.js
should look like this:module.exports = function(api) { api.cache(true); return { presets: ['babel-preset-expo'], plugins: ['react-native-reanimated/plugin'], }; };
and then, for resetting the cache
expo start -c
(since we’re using expo react native)Â
Step 2: Create the DateTimePicker component:
NekoDateTimePicker.js
import Reactfrom 'react'; import { Platform } from 'react-native'; importDateTimePickerfrom '@react-native-community/datetimepicker'; const NekoDateTimePicker = ({ modeType, selectedDate, onChangeDate }) => { return ( <DateTimePicker testID='dateTimePicker' value={selectedDate || newDate()} mode={modeType} is24Hour onChange={onChangeDate} display={Platform.OS === 'ios' ? 'spinner' : 'default'} style={{ alignContent: 'center' }} /> ); }; export default NekoDateTimePicker;
Â
Step 3: For iOS:
Okay, so I created a separate component for iOS:
IOSDateTimePicker.js
That’e because we want to create the custom button for “OKAY” or “CANCEL”, which is already available in Android!
importReact, { useState } from 'react'; import { Text, TouchableOpacity, View } from 'react-native'; import NekoDateTimePicker from './NekoDateTimePicker'; const IOSDateTimePicker = ({ handleCancelDatePicker, handleChangeDob }) => { const [selectedDate, setSelectedDate] = useState(newDate()); const onChangeDate = ({ nativeEvent }) => { const { timestamp } = nativeEvent; const tempDate = newDate(timestamp); if (tempDate) { setSelectedDate(tempDate); } }; return ( <View style={{backgroundColor: '#FFFFFF22', paddingBottom: '5%'}}> <NekoDateTimePicker onChangeDate={onChangeDate} modeType='date' selectedDate={selectedDate} /> <View style={{ justifyContent: 'space-between', marginHorizontal: '10%', flexDirection: 'row', alignItems: 'center' }} > <TouchableOpacity onPress={() => { handleCancelDatePicker(); }} style={{ width: '20%', borderWidth: 1.5, borderColor: '#8D8F91', borderRadius: 10, alignSelf: 'center' }} > <Text style={{ color:'#8D8F91', textAlign: 'center', letterSpacing: -0.24, paddingVertical: 7, fontSize: 12, }} > {' '} 취소 </Text> </TouchableOpacity> <TouchableOpacity onPress={() => { handleChangeDob(selectedDate); }} style={{ width: '20%', borderWidth: 1.5, borderColor: '#8D8F91', borderRadius: 10, alignSelf: 'center' }} > <Text style={{ textAlign: 'center', letterSpacing: -0.24, paddingVertical: 7, fontSize: 12, color:'#8D8F91', }} > 확인 </Text> </TouchableOpacity> </View> </View> ); }; export default IOSDateTimePicker;
Step 4: For Android and the main file:
import React, { useRef, useState, useMemo } from 'react'; import {Platform, SafeAreaView, TouchableOpacity, View, Text,StyleSheet} from 'react-native'; importBottomSheetfrom '@gorhom/bottom-sheet'; import IOSDateTimePicker from './IOSDateTimePicker'; import NekoDateTimePicker from './NekoDateTimePicker'; importDateTimePickerfrom '@react-native-community/datetimepicker'; const DateOfBirth = () => { const dobSheetRef = useRef(null); const dobSheetSnapPoints = useMemo(() => ['1%', '45%'], []); const [dobSheetIndex, setDobSheetIndex] = useState(0); const [date, setDate] = useState(null); const [selectedDate, setSelectedDate] = useState(null); const [isOpenDatePicker, setIsOpenDatePicker] = useState(false); const handleChangeDob = (dob) => { setDate(dob); setDobSheetIndex(0); }; const handleCancelDatePicker = () => { setDobSheetIndex(0); }; // For Platform = Android const onChangeDate = ({ nativeEvent }) => { const { timestamp } = nativeEvent; const dateFromTimestamp = newDate(timestamp); setDate(dateFromTimestamp); setIsOpenDatePicker(false); setSelectedDate(dateFromTimestamp); }; return( <SafeAreaView style={styles.pageView}> <View> <TouchableOpacity style={{ borderRadius: 30, marginTop: '10%', borderWidth: 1, width: '50%', borderColor: '#8D8F91', alignSelf: 'center'}} onPress={()=> { setDobSheetIndex(1); setIsOpenDatePicker(true); }}> <Text style={styles.text }> select date of birth! </Text> </TouchableOpacity> {date && <View> <Text style={[styles.text, {fontSize: 40, marginTop: '10%'}]}> {`${date.getUTCFullYear()}년 ${ date.getMonth() + 1 }월 ${date.getDate()}일 `} </Text> </View>} </View> {Platform.OS === 'ios' && dobSheetIndex === 1 && isOpenDatePicker && ( <BottomSheet key='DOBSettingPopup' ref={dobSheetRef} index={1} style={styles.bottomSheet} snapPoints={dobSheetSnapPoints} backgroundComponent={() => <View style={styles.contentContainer}/> } > <IOSDateTimePicker handleCancelDatePicker={handleCancelDatePicker} handleChangeDob={handleChangeDob} /> </BottomSheet> )} {Platform.OS === 'android' && isOpenDatePicker && ( <View> <NekoDateTimePicker onChangeDate={onChangeDate} modeType='date' selectedDate={selectedDate} /> </View> )} </SafeAreaView> ) }; export default DateOfBirth; const styles =StyleSheet.create({ pageView: { width: '100%', height: '100%', backgroundColor: '#18191a' }, bottomSheet: { backgroundColor: '#121212', shadowColor: '#000', shadowOffset: { width: 0, height: 12 }, shadowOpacity: 0.16, shadowRadius: 16.0, elevation: 20 }, row: { flexDirection: 'row', alignItems: 'center' }, text: { fontSize: 20, color: '#8D8F91', fontFamily: 'space-mono', textAlign: 'center', }, contentContainer: { ...StyleSheet.absoluteFillObject, borderTopLeftRadius: 10, borderTopRightRadius: 10, backgroundColor: '#ffffffDD' } });