Skip to content

Commit f229750

Browse files
committed
memoize callbacks for performance
1 parent d618987 commit f229750

File tree

1 file changed

+80
-65
lines changed

1 file changed

+80
-65
lines changed

packages/jupyter-ai/src/components/mui-extras/simple-autocomplete.tsx

Lines changed: 80 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import React, { useState, useRef, useEffect, useMemo } from 'react';
1+
import React, {
2+
useState,
3+
useRef,
4+
useEffect,
5+
useMemo,
6+
useCallback
7+
} from 'react';
28
import {
39
TextField,
410
MenuItem,
@@ -177,76 +183,85 @@ export function SimpleAutocomplete(
177183
// Determine if menu should be open
178184
const shouldShowMenu = isOpen && filteredOptions.length > 0;
179185

180-
function handleInputChange(event: React.ChangeEvent<HTMLInputElement>): void {
181-
const newValue = event.target.value;
182-
setInputValue(newValue);
183-
setFocusedIndex(-1);
184-
185-
if (!isOpen && newValue.trim() !== '') {
186-
setIsOpen(true);
187-
}
188-
189-
if (props.onChange) {
190-
props.onChange(newValue);
191-
}
192-
}
186+
const handleInputChange = useCallback(
187+
(event: React.ChangeEvent<HTMLInputElement>): void => {
188+
const newValue = event.target.value;
189+
setInputValue(newValue);
190+
setFocusedIndex(-1);
191+
192+
if (!isOpen && newValue.trim() !== '') {
193+
setIsOpen(true);
194+
}
195+
196+
if (props.onChange) {
197+
props.onChange(newValue);
198+
}
199+
},
200+
[isOpen, props.onChange]
201+
);
193202

194-
function handleInputFocus(): void {
203+
const handleInputFocus = useCallback((): void => {
195204
setIsOpen(true);
196-
}
197-
198-
function handleOptionClick(option: AutocompleteOption): void {
199-
setInputValue(option.value);
200-
setIsOpen(false);
201-
setFocusedIndex(-1);
202-
203-
if (props.onChange) {
204-
props.onChange(option.value);
205-
}
206-
207-
if (inputRef.current) {
208-
inputRef.current.blur();
209-
}
210-
}
211-
212-
function handleKeyDown(event: React.KeyboardEvent): void {
213-
if (!shouldShowMenu) {
214-
return;
215-
}
205+
}, []);
206+
207+
const handleOptionClick = useCallback(
208+
(option: AutocompleteOption): void => {
209+
setInputValue(option.value);
210+
setIsOpen(false);
211+
setFocusedIndex(-1);
212+
213+
if (props.onChange) {
214+
props.onChange(option.value);
215+
}
216+
217+
if (inputRef.current) {
218+
inputRef.current.blur();
219+
}
220+
},
221+
[props.onChange]
222+
);
216223

217-
switch (event.key) {
218-
case 'ArrowDown':
219-
event.preventDefault();
220-
setFocusedIndex(prev => {
221-
return prev < filteredOptions.length - 1 ? prev + 1 : 0;
222-
});
223-
break;
224-
225-
case 'ArrowUp':
226-
event.preventDefault();
227-
setFocusedIndex(prev => {
228-
return prev > 0 ? prev - 1 : filteredOptions.length - 1;
229-
});
230-
break;
231-
232-
case 'Enter':
233-
event.preventDefault();
234-
if (focusedIndex >= 0 && focusedIndex < filteredOptions.length) {
235-
handleOptionClick(filteredOptions[focusedIndex]);
236-
}
237-
break;
238-
239-
case 'Escape':
240-
setIsOpen(false);
241-
setFocusedIndex(-1);
242-
break;
243-
}
244-
}
224+
const handleKeyDown = useCallback(
225+
(event: React.KeyboardEvent): void => {
226+
if (!shouldShowMenu) {
227+
return;
228+
}
229+
230+
switch (event.key) {
231+
case 'ArrowDown':
232+
event.preventDefault();
233+
setFocusedIndex(prev => {
234+
return prev < filteredOptions.length - 1 ? prev + 1 : 0;
235+
});
236+
break;
237+
238+
case 'ArrowUp':
239+
event.preventDefault();
240+
setFocusedIndex(prev => {
241+
return prev > 0 ? prev - 1 : filteredOptions.length - 1;
242+
});
243+
break;
244+
245+
case 'Enter':
246+
event.preventDefault();
247+
if (focusedIndex >= 0 && focusedIndex < filteredOptions.length) {
248+
handleOptionClick(filteredOptions[focusedIndex]);
249+
}
250+
break;
251+
252+
case 'Escape':
253+
setIsOpen(false);
254+
setFocusedIndex(-1);
255+
break;
256+
}
257+
},
258+
[shouldShowMenu, filteredOptions, focusedIndex, handleOptionClick]
259+
);
245260

246-
function handleClickAway(): void {
261+
const handleClickAway = useCallback((): void => {
247262
setIsOpen(false);
248263
setFocusedIndex(-1);
249-
}
264+
}, []);
250265

251266
return (
252267
<ClickAwayListener onClickAway={handleClickAway}>

0 commit comments

Comments
 (0)