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

React useEffect非预期触发 实现按钮点击搜索的解决方案

问题根因

异常触发本质是逻辑设计和依赖规则冲突导致的:

  1. 没有拆分「输入框临时输入值」和「实际生效的搜索参数」,输入过程中直接修改被请求逻辑引用的search状态,加上你用// eslint-disable-next-line屏蔽了Hooks依赖校验,导致依赖数组声明和实际用到的响应式值不一致。你虽然没把search加入依赖数组,但每次输入触发组件重渲染后,只要limitPage/page/products任意一个依赖项引用变化,useEffect执行时就会通过闭包拿到最新的search值发请求,造成“输入就触发搜索”的假象。
  2. 你在handleSearch里手动调用getProducts,和useEffect里的请求逻辑重复,同时React的setState是异步批量更新的,调用完setLimitPage/setPage后立刻取状态值会拿到旧值,导致请求参数错误。
修复方案

第一步:拆分两个独立状态

把输入框的临时输入值和实际提交后才生效的搜索词分开,输入过程中不会修改任何useEffect依赖的变量,从根源避免输入时触发副作用:

// 输入框实时绑定的临时值,输入时修改不会触发搜索请求
const [searchInput, setSearchInput] = useState("");
// 点击搜索按钮后才更新的生效搜索参数,仅这个值会参与请求逻辑
const [activeSearch, setActiveSearch] = useState("");

// 其余分页状态保留
const [limitPage, setLimitPage] = useState(10);
const [page, setPage] = useState(1);
// ... 已有的numbers、totalDocs、products等状态

第二步:修正useEffect逻辑,移除依赖屏蔽

不要用eslint注释绕开依赖检查,把所有副作用里用到的响应式值都加入依赖数组,保证依赖关系和实际执行逻辑一致,同时修复原代码里分页计算取值的bug:

useEffect(() => {
  // 统一在这里处理分页、搜索的产品请求
  getProducts(limitPage, page, activeSearch);
  getXlsProducts(100000, 1);

  // 等products数据返回后再计算分页信息
  if (products?.products) {
    const totalDocs = products.products.totalDocs;
    const totalPages = Math.ceil(totalDocs / limitPage);
    const links = [];
    for (let i = 1; i <= totalPages; i++) {
      links[i] = i;
    }
    setNumbers(links);
    setTotalDocs(totalDocs);
    setTotalPages(products.products.totalPages);
    setCurrentPage(products.products.page);
    setNextPage(products.products.hasNextPage);
    setPreviousPage(products.products.hasPrevPage);
  }
// 所有用到的响应式值全加入依赖,不要加eslint屏蔽
}, [limitPage, page, activeSearch, products]);

第三步:修正输入框和搜索按钮逻辑

输入框只绑定临时的searchInput,点击按钮时才把临时值同步到activeSearch,同时重置分页参数,不需要手动调用getProducts——只要依赖项变化,useEffect会自动执行请求:

<div>
  <input
    className="border-1 border-2 border-solid rounded border-slate-300"
    value={searchInput}
    onChange={(e) => setSearchInput(e.target.value)}
  />
  <button onClick={() => {
    // 点击按钮才更新生效的搜索词,同时重置分页
    setActiveSearch(searchInput);
    setLimitPage(10);
    setPage(1);
  }}>
    <FiSearch />
  </button>
</div>
额外注意点
  • 之前独立定义的pages函数可以删掉,所有逻辑收敛到useEffect里即可,避免闭包引用旧状态的问题。
  • 永远不要用// eslint-disable-next-line屏蔽Hooks的依赖校验,绝大多数React useEffect非预期触发问题,都是因为屏蔽校验导致依赖声明和实际逻辑不一致。
  • 不要在useEffect和点击事件里重复写请求逻辑,所有依赖参数变化触发的请求统一交给useEffect处理,事件里只负责更新状态参数即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 22:21:36