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

Material UI Autocomplete防抖功能异常问题求助

解决Material UI Autocomplete防抖失效问题

你的代码问题出在闭包捕获旧状态以及防抖函数的使用方式上,导致每次输入都触发请求,且无法获取最新的输入值。以下是具体问题和修复方案:

核心问题

  1. 闭包捕获旧值:loadData直接引用组件内的inputValue状态,而debouncedLoadData通过useCallback创建时依赖为空数组,它捕获的是组件首次渲染时的loadData,这个函数里的inputValue永远是初始的空字符串。后续输入更新状态后,防抖函数执行时仍使用旧值,导致过滤逻辑错误。
  2. 防抖未正确传递最新输入值:你在handleInputChange中先调用setInputValue(v)(异步更新状态),再调用debouncedLoadData,此时inputValue尚未更新,防抖函数拿到的还是更新前的值。

修复代码

import { useState, useCallback, useEffect } from "react";
import { Autocomplete, TextField } from "@mui/material";
import { debounce } from "lodash";
import topFilms from "./topFilms";

export default function App() {
  const [value, setValue] = useState(null);
  const [inputValue, setInputValue] = useState("");
  const [options, setOptions] = useState([]);

  // 让loadData接收输入值作为参数,不再依赖闭包的inputValue
  const loadData = (searchValue) => {
    const filteredOptions = topFilms.filter((f) =>
      f.title.includes(searchValue)
    );
    console.log(
      `loadData with ${filteredOptions.length} options based on "${searchValue}"`
    );
    setOptions(filteredOptions);
  };

  // 创建防抖函数,接收参数并传递给loadData
  const debouncedLoadData = useCallback(
    debounce((searchValue) => {
      loadData(searchValue);
    }, 1000),
    []
  );

  const handleInputChange = (e, v) => {
    setInputValue(v);
    // 直接传递最新的输入值v给防抖函数
    debouncedLoadData(v);
  };

  const handleChange = (e, v) => {
    setValue(v);
  };

  // 组件卸载时取消防抖,避免内存泄漏
  useEffect(() => {
    return () => {
      debouncedLoadData.cancel();
    };
  }, [debouncedLoadData]);

  return (
    <div className="App">
      <Autocomplete
        value={value}
        inputValue={inputValue}
        onChange={handleChange}
        onInputChange={handleInputChange}
        disablePortal
        options={options}
        getOptionLabel={(option) => option.title}
        isOptionEqualToValue={(option, value) => option.title === value.title}
        id="combo-box-demo"
        renderInput={(params) => <TextField {...params} label="Movie" />}
      />
    </div>
  );
}

关键改动说明

  • 传递输入值参数:将loadData修改为接收searchValue参数,调用防抖函数时直接传入最新的输入值v,彻底避免闭包捕获旧状态的问题。
  • 防抖函数封装:在debounce内部直接调用loadData并传递参数,确保每次触发都使用最新的输入值。
  • 组件卸载清理:添加useEffect在组件卸载时调用debouncedLoadData.cancel(),防止防抖函数在组件卸载后仍执行,造成内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 22:40:39