-
Notifications
You must be signed in to change notification settings - Fork 8.3k
/
Copy pathdebounced_value.ts
59 lines (51 loc) · 1.64 KB
/
debounced_value.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { useState, useMemo, useEffect, useRef } from 'react';
import { debounce } from 'lodash';
/**
* Debounces value changes and updates inputValue on root state changes if no debounced changes
* are in flight because the user is currently modifying the value.
*/
export const useDebouncedValue = <T>(
{
onChange,
value,
}: {
onChange: (val: T) => void;
value: T;
},
{ allowEmptyString }: { allowEmptyString?: boolean } = {}
) => {
const [inputValue, setInputValue] = useState(value);
const unflushedChanges = useRef(false);
const shouldUpdateWithEmptyString = Boolean(allowEmptyString);
// Save the initial value
const initialValue = useRef(value);
const onChangeDebounced = useMemo(() => {
const callback = debounce((val: T) => {
onChange(val);
unflushedChanges.current = false;
}, 256);
return (val: T) => {
unflushedChanges.current = true;
callback(val);
};
}, [onChange]);
useEffect(() => {
if (!unflushedChanges.current && value !== inputValue) {
setInputValue(value);
}
}, [value, inputValue]);
const handleInputChange = (val: T) => {
setInputValue(val);
const valueToUpload = shouldUpdateWithEmptyString
? val ?? initialValue.current
: val || initialValue.current;
onChangeDebounced(valueToUpload);
};
return { inputValue, handleInputChange, initialValue: initialValue.current };
};