@@ -20,18 +20,28 @@ export default class Input extends PureComponent {
20
20
constructor ( props ) {
21
21
super ( props ) ;
22
22
23
+ this . state = {
24
+ pendingEvent : undefined ,
25
+ value : '' ,
26
+ } ;
27
+
23
28
this . input = React . createRef ( ) ;
24
29
25
30
this . onBlur = this . onBlur . bind ( this ) ;
26
31
this . onChange = this . onChange . bind ( this ) ;
27
32
this . onEvent = this . onEvent . bind ( this ) ;
28
33
this . onKeyPress = this . onKeyPress . bind ( this ) ;
34
+ this . debounceEvent = this . debounceEvent . bind ( this ) ;
29
35
this . setInputValue = this . setInputValue . bind ( this ) ;
30
36
this . setPropValue = this . setPropValue . bind ( this ) ;
31
37
}
32
38
33
39
UNSAFE_componentWillReceiveProps ( nextProps ) {
34
40
const { value} = this . input . current ;
41
+ if ( this . state . pendingEvent ) {
42
+ // avoid updating the input while awaiting a debounced event
43
+ return ;
44
+ }
35
45
const valueAsNumber = convert ( value ) ;
36
46
this . setInputValue (
37
47
isNil ( valueAsNumber ) ? value : valueAsNumber ,
@@ -121,6 +131,21 @@ export default class Input extends PureComponent {
121
131
} else {
122
132
this . props . setProps ( { value} ) ;
123
133
}
134
+ this . setState ( { pendingEvent : undefined } ) ;
135
+ }
136
+
137
+ debounceEvent ( seconds = 0.5 ) {
138
+ const { value} = this . input . current ;
139
+
140
+ window . clearTimeout ( this . state ?. pendingEvent ) ;
141
+ const pendingEvent = window . setTimeout ( ( ) => {
142
+ this . onEvent ( ) ;
143
+ } , seconds * 1000 ) ;
144
+
145
+ this . setState ( {
146
+ value,
147
+ pendingEvent,
148
+ } ) ;
124
149
}
125
150
126
151
onBlur ( ) {
@@ -129,7 +154,7 @@ export default class Input extends PureComponent {
129
154
n_blur_timestamp : Date . now ( ) ,
130
155
} ) ;
131
156
this . input . current . checkValidity ( ) ;
132
- return this . props . debounce && this . onEvent ( ) ;
157
+ return this . props . debounce === true && this . onEvent ( ) ;
133
158
}
134
159
135
160
onKeyPress ( e ) {
@@ -140,14 +165,22 @@ export default class Input extends PureComponent {
140
165
} ) ;
141
166
this . input . current . checkValidity ( ) ;
142
167
}
143
- return this . props . debounce && e . key === 'Enter' && this . onEvent ( ) ;
168
+ return (
169
+ this . props . debounce === true && e . key === 'Enter' && this . onEvent ( )
170
+ ) ;
144
171
}
145
172
146
173
onChange ( ) {
147
- if ( ! this . props . debounce ) {
174
+ const { debounce} = this . props ;
175
+ if ( debounce ) {
176
+ if ( Number . isFinite ( debounce ) ) {
177
+ this . debounceEvent ( debounce ) ;
178
+ }
179
+ if ( this . props . type !== 'number' ) {
180
+ this . setState ( { value : this . input . current . value } ) ;
181
+ }
182
+ } else {
148
183
this . onEvent ( ) ;
149
- } else if ( this . props . type !== 'number' ) {
150
- this . setState ( { value : this . input . current . value } ) ;
151
184
}
152
185
}
153
186
}
@@ -188,9 +221,11 @@ Input.propTypes = {
188
221
189
222
/**
190
223
* If true, changes to input will be sent back to the Dash server only on enter or when losing focus.
191
- * If it's false, it will sent the value back on every change.
224
+ * If it's false, it will send the value back on every change.
225
+ * If a number, it will not send anything back to the Dash server until the user has stopped
226
+ * typing for that number of seconds.
192
227
*/
193
- debounce : PropTypes . bool ,
228
+ debounce : PropTypes . oneOfType ( [ PropTypes . bool , PropTypes . number ] ) ,
194
229
195
230
/**
196
231
* A hint to the user of what can be entered in the control . The placeholder text must not contain carriage returns or line-feeds. Note: Do not use the placeholder attribute instead of a <label> element, their purposes are different. The <label> attribute describes the role of the form element (i.e. it indicates what kind of information is expected), and the placeholder attribute is a hint about the format that the content should take. There are cases in which the placeholder attribute is never displayed to the user, so the form must be understandable without it.
0 commit comments