🧳 我的 React Trip 之旅(4):用户打字太快,我的搜索框差点原地爆炸

64 阅读2分钟

防抖、缓存、性能优化——我给搜索框上了三道保险


⌨️ 开头:用户狂敲键盘,我的 API 费差点爆表

测试同学拿着手机,对着搜索框“duang duang duang”猛打:“巴黎、巴厘岛、巴拿马……”

我后台一看:3秒内发了15个请求!Google Suggest 接口差点把我拉黑。

更惨的是,页面卡成 PPT——每次输入都重新渲染建议列表,CPU 直接起飞。

我意识到:搜索框不是输入框,是性能雷区


🛡️ 第一道保险:防抖(Debounce)——让请求“冷静一下”

我写了个自定义 Hook:

// hooks/useDebounce.js
import { useState, useEffect } from 'react';

export default function useDebounce(value, delay = 500) {
  const [debouncedValue, setDebouncedValue] = useState(value);
  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);
    return () => clearTimeout(handler);
  }, [value, delay]);
  return debouncedValue;
}

在搜索组件里:

const [keyword, setKeyword] = useState('');
const debouncedKeyword = useDebounce(keyword, 300);

useEffect(() => {
  if (debouncedKeyword) {
    fetchSuggestions(debouncedKeyword); // 只在用户停手后请求
  }
}, [debouncedKeyword]);

✅ 用户打字时,请求被“憋住”;停手 300ms 后,才真正发出去。
✅ 省流量、省接口、省服务器,三赢!


🧠 第二道保险:useMemo ——别让 React 白干活

即使用了防抖,每次渲染建议列表时,React 还是会重新计算 JSX。

于是我用 useMemo 缓存渲染结果:

const suggestionList = useMemo(() => {
  return suggestions.map(item => (
    <div key={item.id}>{item.title}</div>
  ));
}, [suggestions]);

如果 suggestions 没变,React 就直接复用上次的 DOM,不重算、不重绘


💾 第三道保险:localStorage ——记住用户的“黑历史”

用户搜过“海岛”,下次打开 App 还想搜?别让他重打!

我在 useEffect 里加了缓存逻辑:

// 保存历史
useEffect(() => {
  if (keyword.trim()) {
    const history = JSON.parse(localStorage.getItem('searchHistory') || '[]');
    const newHistory = [keyword, ...history.filter(h => h !== keyword)].slice(0, 10);
    localStorage.setItem('searchHistory', JSON.stringify(newHistory));
  }
}, [keyword]);

// 读取历史
const [history, setHistory] = useState([]);
useEffect(() => {
  const saved = JSON.parse(localStorage.getItem('searchHistory') || '[]');
  setHistory(saved);
}, []);

用户看到“历史记录”,感觉 App 很懂他——这就是用户体验的魔法


🎯 结尾:搜索框不再“炸”,反而成了亮点

现在,我的搜索框:

  • 打字不卡
  • 请求不多
  • 记忆力好

面试官问:“你怎么优化搜索性能?”
我微微一笑:“防抖 + useMemo + localStorage,三件套,稳如老狗。”

下一站,我要挑战最难的部分——让 AI 聊天机器人听懂人话!从 DeepSeek 到 Kimi,我是如何封装一个“万能聊天接口”的?