|
13 | 13 |
|
14 | 14 | const NativeMethodsMixin = require('NativeMethodsMixin');
|
15 | 15 | const React = require('React');
|
| 16 | +const invariant = require('fbjs/lib/invariant'); |
16 | 17 | const PropTypes = require('prop-types');
|
17 | 18 | const StyleSheet = require('StyleSheet');
|
18 | 19 | const View = require('View');
|
@@ -46,7 +47,17 @@ const DatePickerIOS = createReactClass({
|
46 | 47 | /**
|
47 | 48 | * The currently selected date.
|
48 | 49 | */
|
49 |
| - date: PropTypes.instanceOf(Date).isRequired, |
| 50 | + date: PropTypes.instanceOf(Date), |
| 51 | + |
| 52 | + /** |
| 53 | + * Provides an initial value that will change when the user starts selecting |
| 54 | + * a date. It is useful for simple use-cases where you do not want to deal |
| 55 | + * with listening to events and updating the date prop to keep the |
| 56 | + * controlled state in sync. The controlled state has known bugs which |
| 57 | + * causes it to go out of sync with native. The initialDate prop is intended |
| 58 | + * to allow you to have native be source of truth. |
| 59 | + */ |
| 60 | + initialDate: PropTypes.instanceOf(Date), |
50 | 61 |
|
51 | 62 | /**
|
52 | 63 | * Date change handler.
|
@@ -102,34 +113,38 @@ const DatePickerIOS = createReactClass({
|
102 | 113 | };
|
103 | 114 | },
|
104 | 115 |
|
| 116 | + componentDidUpdate: function() { |
| 117 | + if (this.props.date) { |
| 118 | + const propsTimeStamp = this.props.date.getTime(); |
| 119 | + if (this._picker) { |
| 120 | + this._picker.setNativeProps({ |
| 121 | + date: propsTimeStamp, |
| 122 | + }); |
| 123 | + } |
| 124 | + } |
| 125 | + }, |
| 126 | + |
105 | 127 | _onChange: function(event: Event) {
|
106 | 128 | const nativeTimeStamp = event.nativeEvent.timestamp;
|
107 | 129 | this.props.onDateChange && this.props.onDateChange(
|
108 | 130 | new Date(nativeTimeStamp)
|
109 | 131 | );
|
110 | 132 | // $FlowFixMe(>=0.41.0)
|
111 | 133 | this.props.onChange && this.props.onChange(event);
|
112 |
| - |
113 |
| - // We expect the onChange* handlers to be in charge of updating our `date` |
114 |
| - // prop. That way they can also disallow/undo/mutate the selection of |
115 |
| - // certain values. In other words, the embedder of this component should |
116 |
| - // be the source of truth, not the native component. |
117 |
| - const propsTimeStamp = this.props.date.getTime(); |
118 |
| - if (this._picker && nativeTimeStamp !== propsTimeStamp) { |
119 |
| - this._picker.setNativeProps({ |
120 |
| - date: propsTimeStamp, |
121 |
| - }); |
122 |
| - } |
123 | 134 | },
|
124 | 135 |
|
125 | 136 | render: function() {
|
126 | 137 | const props = this.props;
|
| 138 | + invariant( |
| 139 | + props.date || props.initialDate, |
| 140 | + 'A selected date or initial date should be specified.', |
| 141 | + ); |
127 | 142 | return (
|
128 | 143 | <View style={props.style}>
|
129 | 144 | <RCTDatePickerIOS
|
130 | 145 | ref={ picker => { this._picker = picker; } }
|
131 | 146 | style={styles.datePickerIOS}
|
132 |
| - date={props.date.getTime()} |
| 147 | + date={props.date ? props.date.getTime() : props.initialDate ? props.initialDate.getTime() : undefined} |
133 | 148 | locale={props.locale ? props.locale : undefined}
|
134 | 149 | maximumDate={
|
135 | 150 | props.maximumDate ? props.maximumDate.getTime() : undefined
|
|
0 commit comments