Over the years React Native has grown substantially. In an effort to
reduce the size, complexity, and dependencies for React Native a
number of modules were selected to be transformed to community modules. Among
other modules, DatePickerIOS
, DatePickerAndroid
and TimePickerAndroid
were listed. Upcoming feature work for the GoDaddy mobile app
required us to integrate against these modules. What better moment to give back
to the React Native community? We migrated and merged the modules as a means to
contribute to the lean core initiative and join forces with the open
source community of React Native.
The migration effort was outlined in a proposal which lists three distinct goals.
DatePickerIOS
, DatePickerAndroid
and TimePickerAndroid
from
React Native core to a separate module.DatePickerAndroid
and TimePickerAndroid
to match the feature set
for iOS, which supports both date
and time
modes.By merging both Android modules and transforming the functional API to React components there are fewer platform-specific implementations. The overall goal of the new combined module is to be a cross-platform React component. It will try to converge the features of iOS and Android as much as possible.
@react-native-community/datetimepicker
Combined, the set of Android and iOS modules form a new
@react-native-community/datetimepicker
component. To use
this module install it with npm
or yarn
and use react-native link
to
bundle it in your project.
npm install --save @react-native-community/datetimepicker
react-native link @react-native-community/datetimepicker
This will make the React component available for use in your project. Components will be rendered with default native UX for their respective pickers. The example below will render a date picker as Modal on Android and an inline component on iOS.
import DateTimePicker from '@react-native-community/datetimepicker';
function renderMyComponent({ date, onChange }) {
return <DateTimePicker value={date} onChange={onChange} mode="date" />
}
Internally, the module uses React Native’s requireNativeComponent
to require
the renamed native module RNDateTimePicker
. A more detailed description for
installation per platform is available in the documentation of the
component.
The current component and API’s are still part of React Native. However, you can use the modules next to existing implementations. The externalized component has no references to the old code nor shares the old namespace. This makes migrating easier since you don’t have to worry about the exact React Native release that will not include the date and time pickers.
We took care to follow the current community standards as closely as possible. As such the module:
In addition, transforming Mocha tests to Ekke would be a nice new
feature for the component. It would increase confidence in the DateTimePicker
features by running unit tests on an actual device and/or emulator.
The externalization of components presented us with an opportunity to reduce
platform-specific implementations. Android had a function based
API that returns a Promise
and only renders a modal once. That
implementation doesn’t fit the React render lifecycle well since external
state has to be kept to track render state. We’ll demonstrate the Android API
changes later.
For now, let’s focus on the second goal: merging the feature set of both
platforms. The merger of APIs highlighted a few discrepancies. For example, iOS
uses maximumDate
and minimumDate
to restrict range, whereas Android used
maxDate
and minDate
. Similarly, contrary to what the name suggests
DatePickerIOS
is also capable of displaying as time picker by setting
mode=time
or mode=datetime
.
value
Replaces the date
prop. This is a better name for controlling
the value of the time picker. In either case, it has to be a JavaScript
Date
object.onChange
This methods returns both the selected Date
as well as the
SyntheticEvent
whenever the selected date changes. In addition,
onDateChange
was deprecated for iOS. Rather than having two methods,
onChange
now provides the functionality of both. For Android
Promise.resolve
will use this callback whenever a date is selected.mode
Determines what picker should be displayed. The modes date
and
time
are available for both platforms. However, datetime
is only
available for iOS. On Android mode=time
will use the native TimePicker
modal.maximumDate
sets the maximum allowed date or time. This replaces
Android’s maxDate
implementation.minimumDate
sets the minimum allowed date or time. this replaces
Android’s minDate
implementation.display
This new property controls how the picker is displayed for
Android which supports displaying pickers as spinner
or calendar
.To make the Android API a better fit for the React render lifecycle it has to
act more like a renderable React Component, e.g. <DateTimePicker />
. This is
achieved by storing a reference to an open instance of the modal whereas the
original implementation would dismiss the picker modal on each consecutive call
to the API. In the new implementation the open instance of the modal will be
updated with the value from provided properties.
public class RNDatePickerDialogFragment extends DialogFragment {
private DatePickerDialog instance;
@Nullable
private OnDateSetListener mOnDateSetListener;
@Nullable
private OnDismissListener mOnDismissListener;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Bundle args = getArguments();
instance = createDialog(args, getActivity(), mOnDateSetListener);
return instance;
}
...
}
The component comes with a runnable React Native example app that uses the new component. Below are examples of the date and time picker on both platforms.
This contribution to the lean core initiative will allow the community to continue adding new features and bug fixes to the React Native DateTimePicker component without needing a new release of React Native itself.
Daniel Sanudo Vacas helped writing documentation and detox tests for the new module.