{
{props.projectsData
.filter(project => {
if (
- //prettier-ignore
- props.formatText(project.projectName).indexOf(props.formatText(props.searchText)) >-1
+ props.formatText(project.projectName).includes(props.formatText(debouncedSearchText))
) {
return project;
}
@@ -75,7 +93,7 @@ const AddProjectsAutoComplete = React.memo(props => {
))}
{props.projectsData.every(
- item => props.formatText(item.projectName) !== props.formatText(props.searchText),
+ item => props.formatText(item.projectName) !== props.formatText(debouncedSearchText),
) && (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
{
props.setIsOpenDropdown(true);
}}
>
- Create new project: {props.searchText}
+ Create new project: {debouncedSearchText}
)}
diff --git a/src/components/UserProfile/TeamsAndProjects/AddTeamsAutoComplete.jsx b/src/components/UserProfile/TeamsAndProjects/AddTeamsAutoComplete.jsx
index 34d704a5af..4be7851820 100644
--- a/src/components/UserProfile/TeamsAndProjects/AddTeamsAutoComplete.jsx
+++ b/src/components/UserProfile/TeamsAndProjects/AddTeamsAutoComplete.jsx
@@ -1,11 +1,13 @@
-import React, { useRef, useEffect } from 'react';
+import React, { useRef, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { Dropdown, Input } from 'reactstrap';
+import debounce from 'lodash/debounce';
import './TeamsAndProjects.module.css';
import { useSelector } from 'react-redux';
import appStyles from '~/App.module.css';
const TEAM_NAME_MAX_LENGTH = 100;
+const SEARCH_DEBOUNCE_MS = 300;
// eslint-disable-next-line react/display-name
const AddTeamsAutoComplete = React.memo((props) => {
@@ -27,11 +29,27 @@ const AddTeamsAutoComplete = React.memo((props) => {
const normalize = (s) =>
(s ?? '').toString().toLowerCase().trim().replace(/\s+/g, ' ');
+ // The input stays fully responsive via searchText; only the (re)filtering of the
+ // suggestion list is debounced so rapid keystrokes don't recompute it every time.
+ const [debouncedSearchText, setDebouncedSearchText] = useState(searchText);
+ const debouncedSetSearchText = useRef(
+ debounce((value) => setDebouncedSearchText(value), SEARCH_DEBOUNCE_MS, {
+ leading: true,
+ trailing: true,
+ }),
+ ).current;
+
+ useEffect(() => {
+ debouncedSetSearchText(searchText);
+ }, [searchText, debouncedSetSearchText]);
+
+ useEffect(() => () => debouncedSetSearchText.cancel(), [debouncedSetSearchText]);
+
const suggestions = React.useMemo(() => {
- const q = normalize(searchText);
+ const q = normalize(debouncedSearchText);
if (!q) return allTeams; // show all when empty
return allTeams.filter((t) => normalize(t.teamName).includes(q));
- }, [allTeams, searchText]);
+ }, [allTeams, debouncedSearchText]);
const handlePick = (team) => {
onDropDownSelect(team);