Skip to content

Commit 23a3f43

Browse files
committed
fix menuex search too slow
1 parent f7f64ca commit 23a3f43

File tree

3 files changed

+24
-13
lines changed

3 files changed

+24
-13
lines changed

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
"npm-v-patch": "npm version patch && git push origin main:main && git push --tags",
2525
"npm-v-major": "npm version major && git push origin main:main && git push --tags",
2626
"npm-publish": "npm publish --access public",
27-
"reset-repo": "git fetch origin && git reset --hard origin/main"
27+
"reset-repo": "git fetch origin && git reset --hard origin/main",
28+
"clear-npm-cache": "npm cache clean --force"
2829
},
2930
"repository": {
3031
"type": "git",
@@ -81,4 +82,4 @@
8182
"react": ">=16.14.0 <19.0.0",
8283
"react-dom": ">=16.14.0 <19.0.0"
8384
}
84-
}
85+
}

src/controls/menu.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { Menu, MenuDivider, MenuGroup, MenuGroupHeader, MenuItem, MenuList, Menu
22
import { ChevronLeftRegular, ChevronRightRegular } from '@fluentui/react-icons';
33
import { IDictionary, isNotEmptyArray, isNotEmptyString, isNullOrEmptyString, isNullOrUndefined, isNumber, isString, isUndefined, jsonClone, stopEvent } from '@kwiz/common';
44
import React from 'react';
5-
import { useKWIZFluentContext } from '../helpers/context-internal';
65
import { useStateEX } from '../helpers';
6+
import { useKWIZFluentContext } from '../helpers/context-internal';
77
import { ButtonEX, ButtonEXProps } from './button';
88
import { Horizontal } from './horizontal';
99
import { Search } from './search';
@@ -113,7 +113,7 @@ export const MenuEx: React.FunctionComponent<React.PropsWithChildren<IProps>> =
113113

114114
const paged = menuItems.length > pageSize;
115115
const filtered = menuItems.length > filterThreshold || !isNullOrEmptyString(myLevelFilter);
116-
const filterControl = filtered && <Search value={myLevelFilter || ""} onChangeDeferred={(newValue) => {
116+
const filterControl = filtered && <Search defaultValue={myLevelFilter || ""} onChangeDeferred={(newValue) => {
117117
const s = jsonClone(filterPerLevel);
118118
s[level] = newValue ? newValue.toLowerCase() : "";
119119
setFilterPerLevel(s);

src/controls/search.tsx

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { Input, InputProps, makeStyles, mergeClasses } from '@fluentui/react-components';
22
import { DismissRegular, SearchRegular } from "@fluentui/react-icons";
3-
import { debounce, isNullOrEmptyString } from '@kwiz/common';
4-
import React, { useRef } from 'react';
3+
import { debounce, isNullOrEmptyString, isNullOrUndefined } from '@kwiz/common';
4+
import React, { useEffect, useRef } from 'react';
55
import { GetLogger } from '../_modules/config';
6+
import { useEffectOnlyOnMount, useStateEX } from '../helpers';
67
import { mixins } from '../styles/styles';
78
const logger = GetLogger("Search");
89

@@ -36,26 +37,35 @@ export const Search: React.FunctionComponent<React.PropsWithChildren<IProps>> =
3637
React.useEffect(() => { refonChangeDeferred.current = props.onChangeDeferred; }, [props.onChangeDeferred]);
3738

3839
//cannot call debounce every render, since it won't be the same debounced instance...
39-
var notifyParent = React.useMemo(() => debounce(v => {
40+
var notifyParent = React.useCallback(debounce(v => {
4041
logger.log(`Set: ${v}`);
4142
//Call the latest ref - we don't want to call an old version of this function
4243
refonChangeDeferred.current?.(v);
4344
}, delay * 1000), [delay]);
4445

45-
const currentValue = props.value || "";
46+
const [currentValue, setCurrentValue] = useStateEX(props.value || props.defaultValue || "", { skipUpdateIfSame: true });
47+
useEffect(() => {
48+
if (!isNullOrUndefined(props.value))
49+
setCurrentValue(props.value);
50+
}, [props.value]);
51+
52+
var changeValue = React.useCallback((newValue: string) => {
53+
newValue = newValue || "";//no null or undefined here
54+
setCurrentValue(newValue);//keep our state updated in sync
55+
props.onChange?.(newValue);//if parent is using search as managed control, keep it up to date in sync
56+
notifyParent(newValue);//trigger a search async
57+
}, useEffectOnlyOnMount);
4658

4759
return (
48-
<Input {...props} value={currentValue} onChange={(e, data) => {
49-
props.onChange?.(data.value);
50-
notifyParent(data.value);
60+
<Input {...props} autoFocus defaultValue={undefined} value={currentValue} onChange={(e, data) => {
61+
changeValue(data.value);
5162
}}
5263
className={mergeClasses(cssNames.root, props.main && cssNames.main)}
5364
contentBefore={!isNullOrEmptyString(currentValue) ? undefined : <SearchRegular className={cssNames.searchIcon} />}
5465
contentAfter={isNullOrEmptyString(currentValue)
5566
? undefined
5667
: <DismissRegular className={cssNames.clickable} onClick={() => {
57-
props.onChange?.("");
58-
notifyParent("");
68+
changeValue("");
5969
}} />
6070
} />
6171
);

0 commit comments

Comments
 (0)