Skip to content

Commit 85dbb87

Browse files
committed
Update debounce prop of Textarea + tests
1 parent df05661 commit 85dbb87

File tree

4 files changed

+46
-10
lines changed

4 files changed

+46
-10
lines changed

src/components/input/Input.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ const Input = props => {
6767
if (debounce) {
6868
if (Number.isFinite(debounce)) {
6969
clearTimeout(debounceRef.current);
70-
debounceRef.current = setTimeout(onEvent, debounce * 1000);
70+
debounceRef.current = setTimeout(onEvent, debounce);
7171
}
7272
} else {
7373
onEvent();
@@ -604,7 +604,7 @@ Input.propTypes = {
604604
* focus. If it's false, it will sent the value back on every
605605
* change. If debounce is a number, the value will be sent to the
606606
* server only after the user has stopped typing for that number
607-
* of seconds.
607+
* of milliseconds.
608608
*/
609609
debounce: PropTypes.oneOfType([PropTypes.bool, PropTypes.number]),
610610

src/components/input/Textarea.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {useEffect, useState} from 'react';
1+
import React, {useEffect, useRef, useState} from 'react';
22
import PropTypes from 'prop-types';
33
import {omit} from 'ramda';
44
import classNames from 'classnames';
@@ -43,6 +43,7 @@ const Textarea = props => {
4343
...otherProps
4444
} = props;
4545
const [valueState, setValueState] = useState(value || '');
46+
const debounceRef = useRef(null);
4647

4748
useEffect(() => {
4849
if (value !== valueState) {
@@ -53,7 +54,15 @@ const Textarea = props => {
5354
const onChange = e => {
5455
const newValue = e.target.value;
5556
setValueState(newValue);
56-
if (!debounce && setProps) {
57+
if (debounce) {
58+
if (Number.isFinite(debounce)) {
59+
clearTimeout(debounceRef.current);
60+
debounceRef.current = setTimeout(
61+
() => setProps({value: newValue}),
62+
debounce
63+
);
64+
}
65+
} else {
5766
setProps({value: newValue});
5867
}
5968
};
@@ -435,8 +444,10 @@ Textarea.propTypes = {
435444
n_clicks_timestamp: PropTypes.number,
436445

437446
/**
438-
* If true, changes to input will be sent back to the Dash server only on enter or when losing focus.
439-
* If it's false, it will sent the value back on every change.
447+
* If true, changes to input will be sent back to the Dash server only on enter or
448+
* when losing focus. If it's false, it will sent the value back on every change.
449+
* If debounce is a number, the value will be sent to the server only after the user
450+
* has stopped typing for that number of milliseconds
440451
*/
441452
debounce: PropTypes.bool,
442453

src/components/input/__tests__/Input.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,14 +195,14 @@ describe('Input', () => {
195195
});
196196
});
197197

198-
describe('debounce', () => {
198+
describe('numeric debounce', () => {
199199
let inputElement, mockSetProps;
200200

201201
beforeEach(() => {
202202
jest.useFakeTimers();
203203
mockSetProps = jest.fn();
204204
const {container} = render(
205-
<Input setProps={mockSetProps} value="" debounce={2} />
205+
<Input setProps={mockSetProps} value="" debounce={2000} />
206206
);
207207
inputElement = container.firstChild;
208208
});
@@ -215,7 +215,7 @@ describe('Input', () => {
215215
expect(inputElement).toHaveValue('some-input-value');
216216
act(() => jest.advanceTimersByTime(1000));
217217
expect(mockSetProps.mock.calls).toHaveLength(0);
218-
act(() => jest.advanceTimersByTime(4000));
218+
act(() => jest.advanceTimersByTime(1000));
219219
expect(mockSetProps.mock.calls).toHaveLength(1);
220220
});
221221
});

src/components/input/__tests__/Textarea.test.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
import React from 'react';
6-
import {render, fireEvent} from '@testing-library/react';
6+
import {act, render, fireEvent} from '@testing-library/react';
77
import userEvent from '@testing-library/user-event';
88
import Textarea from '../Textarea';
99

@@ -218,5 +218,30 @@ describe('Textarea', () => {
218218
expect(mockSetProps.mock.calls).toHaveLength(1);
219219
});
220220
});
221+
222+
describe('numeric debounce', () => {
223+
let textarea, mockSetProps;
224+
225+
beforeEach(() => {
226+
jest.useFakeTimers();
227+
mockSetProps = jest.fn();
228+
const {container} = render(
229+
<Textarea setProps={mockSetProps} value="" debounce={2000} />
230+
);
231+
textarea = container.firstChild;
232+
});
233+
234+
test('call setProps after delay if debounce is number', () => {
235+
fireEvent.change(textarea, {
236+
target: {value: 'some-input-value'}
237+
});
238+
expect(mockSetProps.mock.calls).toHaveLength(0);
239+
expect(textarea).toHaveValue('some-input-value');
240+
act(() => jest.advanceTimersByTime(1000));
241+
expect(mockSetProps.mock.calls).toHaveLength(0);
242+
act(() => jest.advanceTimersByTime(1000));
243+
expect(mockSetProps.mock.calls).toHaveLength(1);
244+
});
245+
});
221246
});
222247
});

0 commit comments

Comments
 (0)