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

Next.js应用中useInfiniteHits的showMore移除URL查询参数问题

在Next.js中使用Algolia无限滚动时URL丢失query参数的问题

问题场景

我在Next.js项目里用Algolia的useInfiniteHits实现无限滚动,核心代码如下:

import { useInfiniteHits, UseInfiniteHitsProps } from 'react-instantsearch-hooks-web'
const { hits, isLastPage, showMore } = useInfiniteHits()

点击调用showMore()的"加载更多"按钮后,URL里的query参数会被莫名移除:

  • 点击前:http://localhost:3000/search?query=polo%20shirts
  • 点击后:http://localhost:3000/search?page=2

这会导致刷新页面时丢失筛选条件,因为query参数没了,只能返回未过滤的通用结果。

我尝试写了自定义处理函数想保留参数,但因为竞态条件,query还是会被移除:

const handleShowMore = () => {
    // Load more results
    showMore()

    // Get the current page and update it, ensure the query is preserved
    const currentQuery = Array.isArray(router.query.query) ? router.query.query[0] : router.query.query || ''

    // Ensure the query includes the current query and page number
    const updatedQuery = { ...router.query, query: currentQuery }

    // Push the updated URL with the preserved query and new page number
    router.push(
      {
        pathname: router.pathname, // Retain the current pathname
        query: updatedQuery, // Update the query with new page and preserved query
      },
      undefined,
      { shallow: true }, // Shallow routing to avoid full page reload
    )
  }

问题原因

Algolia的showMore()会自动更新URL的page参数,但它只维护自身管理的路由参数,不会保留原本的query参数。而你手动更新路由的操作和showMore()的路由更新存在竞态,showMore()的后续操作会覆盖你手动添加的query参数。

解决方案

不要手动修正路由,而是通过给Algolia的InstantSearch组件配置自定义history对象,让它在更新URL时自动合并现有参数。

实现步骤

  1. 创建自定义history处理函数
    在你的搜索页面组件里,定义一个自定义的history对象,重写push和replace方法,让它们合并现有URL参数和Algolia生成的参数:
import { useRouter } from 'next/router';
import { InstantSearch, useInfiniteHits } from 'react-instantsearch-hooks-web';
import algoliasearch from 'algoliasearch';

// 初始化Algolia搜索客户端
const searchClient = algoliasearch('YOUR_APP_ID', 'YOUR_SEARCH_API_KEY');

export default function SearchPage() {
  const router = useRouter();
  const { hits, isLastPage, showMore } = useInfiniteHits();

  // 自定义history,确保Algolia更新路由时保留原有query参数
  const customHistory = {
    push: (routeState) => {
      // 合并现有query和Algolia的路由状态参数
      const newQuery = {
        ...router.query,
        ...routeState,
      };
      // 清理空值参数(可选,避免URL里出现空参数)
      Object.keys(newQuery).forEach(key => {
        if (!newQuery[key]) delete newQuery[key];
      });

      router.push(
        { pathname: router.pathname, query: newQuery },
        undefined,
        { shallow: true }
      );
    },
    replace: (routeState) => {
      const newQuery = {
        ...router.query,
        ...routeState,
      };
      Object.keys(newQuery).forEach(key => {
        if (!newQuery[key]) delete newQuery[key];
      });

      router.replace(
        { pathname: router.pathname, query: newQuery },
        undefined,
        { shallow: true }
      );
    },
    // 实现history接口必需的其他方法
    location: { search: router.asPath.split('?')[1] || '' },
    listen: () => () => {},
  };

  return (
    <InstantSearch
      searchClient={searchClient}
      indexName="YOUR_INDEX_NAME"
      history={customHistory}
    >
      {/* 你的搜索结果展示组件 */}
      <div className="hits-container">
        {hits.map(hit => (
          <div key={hit.objectID}>{hit.name}</div>
        ))}
      </div>
      
      {/* 加载更多按钮,直接调用showMore即可 */}
      <button onClick={showMore} disabled={isLastPage}>
        {isLastPage ? '没有更多结果' : '加载更多'}
      </button>
    </InstantSearch>
  );
}
  1. 移除自定义的handleShowMore
    直接使用原生的showMore()即可,不需要再手动处理路由,自定义的history会自动帮你合并参数,保证URL里同时保留query和page参数。

方案原理

Algolia的InstantSearch组件会使用你传入的history对象来管理路由变化,自定义的push和replace方法会把原本的query参数和Algolia生成的page参数合并后再更新URL,从根源上避免了竞态条件,同时保证所有必要参数都保留在URL中,刷新页面也不会丢失筛选条件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 11:04:50