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

如何在Next.js中通过搜索栏调用本地API按搜索词查询商品标题

Next.js 商品标题检索功能正确实现方案

原有代码问题汇总

  • API路由逻辑错误:本地已经导入商品数据源,反而发起自调用fetch请求,且错误将整个query对象拼接为路径参数,无法正确读取搜索关键词
  • 前端请求格式错误:URL参数写为?=,缺少参数名,搜索词无法被后端接收
  • 缺少核心匹配逻辑:没有实现标题关键词模糊匹配的过滤规则
  • 缺少性能优化:输入时直接触发请求,没有防抖控制,会产生大量无效请求
  • 缺少结果状态:请求拿到数据后没有存储,无法渲染搜索结果

修正后的API路由代码

文件路径:pages/api/products.js

import { products } from './dataproducts'

export default async function handler(req, res) {
  const { search } = req.query
  // 未传入搜索关键词时返回全量商品
  if (!search?.trim()) {
    return res.status(200).json(products)
  }
  // 大小写不敏感的模糊匹配
  const keyword = search.trim().toLowerCase()
  const matchList = products.filter(item => item.title.toLowerCase().includes(keyword))
  res.status(200).json(matchList)
}

修正后的搜索栏组件代码

文件路径:components/SearchBar.js

import { useState, useEffect } from 'react'
import styles from '../../styles/SearchBar.module.css'

function SearchBar() {
  const [query, setQuery] = useState('')
  const [resultList, setResultList] = useState([])
  const [debounceTimer, setDebounceTimer] = useState(null)

  const handleInput = (e) => {
    const inputVal = e.target.value
    setQuery(inputVal)
    // 清除上一次的请求定时器
    if (debounceTimer) clearTimeout(debounceTimer)
    // 输入长度不足时清空结果,不发起请求
    if (inputVal.trim().length <= 3) {
      setResultList([])
      return
    }
    // 输入停止300ms后再发起请求,减少无效调用
    const timer = setTimeout(async () => {
      try {
        const res = await fetch(`http://localhost:3000/api/products?search=${encodeURIComponent(inputVal.trim())}`)
        const data = await res.json()
        setResultList(data)
      } catch (err) {
        console.error('搜索失败:', err)
        setResultList([])
      }
    }, 300)
    setDebounceTimer(timer)
  }

  // 组件卸载时清除定时器,避免内存泄漏
  useEffect(() => {
    return () => debounceTimer && clearTimeout(debounceTimer)
  }, [debounceTimer])

  return (
    <div className={styles.searchContainer}>
      <input 
        className={styles.input} 
        onChange={handleInput}
        id='productSearch'
        type="search" 
        name="search"
        value={query} 
        placeholder="Nombre producto..." 
      />
      {/* 搜索结果列表 */}
      {resultList.length > 0 && (
        <ul className={styles.resultBox}>
          {resultList.map(product => (
            <li key={product.id} className={styles.resultItem}>
              <img src={product.image} alt={product.title} width={48} height={48} />
              <div>
                <p className={styles.productTitle}>{product.title}</p>
                <p className={styles.productPrice}>€{product.price}</p>
              </div>
            </li>
          ))}
        </ul>
      )}
      {/* 无匹配结果提示 */}
      {query.trim().length > 3 && resultList.length === 0 && (
        <div className={styles.emptyTip}>No se encontraron productos coincidentes</div>
      )}
    </div>
  )
}

export default SearchBar

关键逻辑说明

  • API层直接基于本地数据源做过滤,去掉冗余的自调用fetch,响应速度更快
  • 前后端统一使用search作为参数名,修正URL参数格式错误,搜索词可正常传递
  • 匹配逻辑统一转小写后做包含判断,支持大小写不敏感的模糊检索
  • 加入输入防抖机制,用户连续输入时不会重复发起请求,降低服务端压力
  • 补全结果状态管理,支持匹配结果渲染、空结果提示,搜索交互完整可用
  • 关键词做URL编码处理,避免特殊字符导致接口请求异常

内容的提问来源于stack exchange,提问作者Francisco José López Laperal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 20:27:21