1
1
import { Input , InputProps , makeStyles , mergeClasses } from '@fluentui/react-components' ;
2
2
import { DismissRegular , SearchRegular } from "@fluentui/react-icons" ;
3
- import { debounce , isFunction , isNullOrEmptyString , isUndefined } from '@kwiz/common' ;
4
- import React , { useState } from 'react' ;
3
+ import { debounce , isNullOrEmptyString } from '@kwiz/common' ;
4
+ import React , { useRef } from 'react' ;
5
5
import { GetLogger } from '../_modules/config' ;
6
- import { useStateEX } from '../helpers' ;
7
6
import { mixins } from '../styles/styles' ;
8
7
const logger = GetLogger ( "Search" ) ;
9
8
@@ -16,55 +15,47 @@ const useStyles = makeStyles({
16
15
} ,
17
16
} )
18
17
19
- interface IProps extends InputProps {
18
+ interface IProps extends Omit < InputProps , "onChange" > {
20
19
main ?: boolean ;
20
+ /** number of seconds to debounce the deferred event */
21
21
delay ?: number ;
22
22
/** if changing the value in the caller - change this prop to reset */
23
23
resetValue ?: string ;
24
24
onChangeDeferred ?: ( newValue : string ) => void ;
25
- onChangeSync ?: ( newValue : string ) => void ;
25
+ onChange ?: ( newValue : string ) => void ;
26
26
}
27
27
28
28
/** value is set on first load. to change the value after it was first set - change the compoenet's key. */
29
29
export const Search : React . FunctionComponent < React . PropsWithChildren < IProps > > = ( props ) => {
30
30
const cssNames = useStyles ( ) ;
31
31
32
- const [ resetKey , setResetKey ] = useState ( 1 ) ;
33
-
34
32
let delay = props . delay || 1 ;
35
33
34
+ let refonChangeDeferred = useRef ( props . onChangeDeferred ) ;
35
+ //keep updating the ref
36
+ React . useEffect ( ( ) => { refonChangeDeferred . current = props . onChangeDeferred ; } , [ props . onChangeDeferred ] ) ;
37
+
36
38
//cannot call debounce every render, since it won't be the same debounced instance...
37
39
var notifyParent = React . useMemo ( ( ) => debounce ( v => {
38
40
logger . log ( `Set: ${ v } ` ) ;
39
- props . onChangeDeferred ( v ) ;
41
+ //Call the latest ref - we don't want to call an old version of this function
42
+ refonChangeDeferred . current ?.( v ) ;
40
43
} , delay * 1000 ) , [ delay ] ) ;
41
44
42
- let [ value , setValue ] = useStateEX ( props . value || "" , {
43
- onChange : newValue => {
44
- if ( isFunction ( props . onChangeSync ) ) props . onChangeSync ( newValue as string ) ;
45
- if ( isFunction ( props . onChangeDeferred ) ) notifyParent ( newValue ) ;
46
- return newValue ;
47
- }
48
- } ) ;
49
-
50
- //once props change, reset this control value to match
51
- React . useEffect ( ( ) => {
52
- if ( ! isUndefined ( props . resetValue ) )
53
- setValue ( props . resetValue ) ;
54
- //todo: bug: setting value does not sync into the text box
55
- setResetKey ( resetKey + 1 )
56
- } , [ props . resetValue ] ) ;
45
+ const currentValue = props . value || "" ;
57
46
58
47
return (
59
- < Input key = { resetKey } { ...props } value = { value } onChange = { ( e , data ) => setValue ( data . value ) }
48
+ < Input { ...props } value = { currentValue } onChange = { ( e , data ) => {
49
+ props . onChange ?.( data . value ) ;
50
+ notifyParent ( data . value ) ;
51
+ } }
60
52
className = { mergeClasses ( cssNames . root , props . main && cssNames . main ) }
61
- contentBefore = { ! isNullOrEmptyString ( value ) ? undefined : < SearchRegular className = { cssNames . searchIcon } /> }
62
- contentAfter = { isNullOrEmptyString ( value )
53
+ contentBefore = { ! isNullOrEmptyString ( currentValue ) ? undefined : < SearchRegular className = { cssNames . searchIcon } /> }
54
+ contentAfter = { isNullOrEmptyString ( currentValue )
63
55
? undefined
64
56
: < DismissRegular className = { cssNames . clickable } onClick = { ( ) => {
65
- setValue ( "" ) ;
66
- //todo: bug: setting value does not sync into the text box
67
- setResetKey ( resetKey + 1 )
57
+ props . onChange ?.( "" ) ;
58
+ notifyParent ( "" ) ;
68
59
} } />
69
60
} />
70
61
) ;
0 commit comments