You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React输入文本变更时隐藏下拉菜单的技术求助

实现输入变更时立即隐藏下拉菜单的防抖搜索组件

要实现输入框字符变更时立即隐藏下拉菜单,直到防抖后的搜索结果返回,核心思路是对比实时输入值与已完成防抖处理的查询值,只有当两者一致时才展示下拉菜单。具体修改步骤如下:

1. 更新上下文类型与Provider

首先需要将防抖后的查询值appliedQuery添加到上下文,让子组件能获取到这个值进行判断:

修改PeopleContext.tsx:

import React, {
  createContext,
  useState,
  useCallback,
  useMemo,
  ReactNode,
} from 'react';
import debounce from 'lodash/debounce';
import { Person } from '../types/Person';
import { peopleFromServer } from '../data/people';

// 1. 更新上下文类型,新增appliedQuery字段
interface PeopleContextType {
  input: string;
  setInput: (query: string) => void;
  applyQueryWithDebounce: (query: string) => void;
  handleClick: (person: string) => void;
  filteredPeople: Person[];
  selectedPerson: string;
  appliedQuery: string; // 新增字段
}

const PeopleContext = createContext<PeopleContextType>({} as PeopleContextType);

export const PeopleProvider: React.FC<{ children: ReactNode }> = ({
  children,
}) => {
  const [people, setPeople] = useState<Person[] | null>(peopleFromServer);
  const [input, setInput] = useState<string>('');
  const [selectedPerson, setSelectedPerson]
    = useState<string>('No selected person');
  const [appliedQuery, setAppliedQuery] = useState<string>('');

  const applyQueryWithDebounce = useCallback(
    debounce(setAppliedQuery, 1000), [],
  );

  const filteredPeople = useMemo(() => {
    return peopleFromServer.filter((person) => person.name
      .toLowerCase()
      .includes(appliedQuery.toLowerCase()));
  }, [people, appliedQuery]);

  const handleClick = useCallback((person: string) => {
    setSelectedPerson(person);
    setPeople([]);
    setInput('');
  }, []);

  return (
    <PeopleContext.Provider
      value={{
        input,
        setInput,
        applyQueryWithDebounce,
        handleClick,
        filteredPeople,
        selectedPerson,
        appliedQuery, // 2. 将appliedQuery加入上下文提供的值中
      }}
    >
      {children}
    </PeopleContext.Provider>
  );
};

export default PeopleContext;

2. 修改下拉菜单的显示条件

在People组件中,获取appliedQuery,并修改下拉菜单的渲染条件:只有当实时输入input不为空,且与防抖后的appliedQuery完全一致时,才展示下拉菜单。

修改People.tsx:

import React, { useContext } from 'react';
import cn from 'classnames';
import PeopleContext from '../contexts/PeopleContext';

export const People = React.memo(() => {
  const {
    input,
    setInput,
    applyQueryWithDebounce,
    filteredPeople,
    handleClick,
    appliedQuery, // 1. 从上下文获取appliedQuery
  } = useContext(PeopleContext);

  const handleInput = (event: React.ChangeEvent<HTMLInputElement>) => {
    const userInput = event.target.value;

    applyQueryWithDebounce(userInput);

    setInput(userInput);
  };

  return (
    <div className="dropdown is-active">
      <div className="dropdown-trigger">
        <input
          type="search"
          placeholder="Enter the name"
          className="input"
          value={input}
          onChange={handleInput}
        />
      </div>

      {/* 2. 修改显示条件:input不为空且与appliedQuery一致 */}
      {input && input === appliedQuery && (
        <div className="dropdown-menu" role="menu">
          <div className="dropdown-content">
            {filteredPeople.length > 0
              && filteredPeople.map((person) => (
                <button
                  key={person.slug}
                  type="button"
                  className="dropdown-item person-input-item"
                  onClick={() => {
                    handleClick(
                      `${person.name} (${person.born} - ${person.died})`,
                    );
                  }}
                >
                  <p
                    className={cn('has-text-link', {
                      'has-text-danger': person.sex === 'f',
                    })}
                  >
                    {person.name}
                  </p>
                </button>
              ))}

            {!filteredPeople.length && (
              <p className="dropdown-item has-text-danger">
                No matching suggestions
              </p>
            )}
          </div>
        </div>
      )}
    </div>
  );
};

改动说明

  • 当用户输入字符时,input会实时更新,而appliedQuery因为防抖延迟还未同步,此时input !== appliedQuery,下拉菜单隐藏;
  • 防抖时间结束后,appliedQuery更新为当前input的值,两者相等,下拉菜单重新展示搜索结果;
  • 若用户连续输入,每次输入都会触发input更新,但只有最后一次输入的防抖触发后,appliedQuery才会匹配当前input,确保下拉菜单只在搜索结果准备好后显示。

内容的提问来源于stack exchange,提问作者Yevhen Petrovskyi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 02:53:11