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

react-select-async-paginate滚动不加载 万级下拉无卡顿方案

问题根因

你的代码有3个核心错误,导致分页加载逻辑不生效:

  • 违反React Hook使用规则:在普通异步函数LoadOptions中调用useState,Hook仅能在React组件或自定义Hook的顶层执行,在普通异步函数中调用不仅会抛出运行时错误,还会导致你定义的prevLast状态每次函数执行时都被重置为0,完全无法持久化分页偏移量。
  • 未使用组件官方的分页状态传递机制:react-select-async-paginate的分页游标不需要开发者自行在函数内存储,而是通过loadOptions的第三个入参(上一次请求返回的附加状态)、以及返回值中的additional字段在组件内部维护,你没有实现这套逻辑,组件无法获取下一页的请求参数,自然不会在滚动时触发后续加载。
  • 分页逻辑硬编码错误:之前的偏移量计算逻辑错误(误将单页数据长度作为下一次偏移量,而非累计已加载总数),且hasMore固定为true,数据全部加载完成后还会持续触发无效请求。
正确实现代码

首先调整LoadOptions逻辑,移除所有Hook调用,通过组件约定的参数传递分页状态,建议固定单页加载条数为50-100,平衡请求次数和渲染性能:

const sleep = (ms) =>
  new Promise((resolve) => {
    setTimeout(resolve, ms);
  });

const baseurl = "http://localhost:5000/api";
// 单页加载条数,建议设置为50-100
const PAGE_SIZE = 80;

const LoadOptions = async (search, prevOptions, { offset }) => {
  await sleep(300);
  // 向后端传递偏移量、单页大小、搜索关键词
  const response = await fetch(
    `${baseurl}/pdt?offset=${offset}&limit=${PAGE_SIZE}&keyword=${encodeURIComponent(search)}`
  );
  const pList = await response.json();
  
  const pdtList = pList.map(item => ({
    label: item.pdtno,
    value: item.pdtno
  }));

  // 返回数据长度小于单页大小,说明已经是最后一页
  const hasMore = pdtList.length === PAGE_SIZE;
  return {
    options: pdtList,
    hasMore,
    // 传递下一次请求的偏移量,存在additional字段中由组件维护
    additional: {
      offset: offset + pdtList.length
    }
  };
};

export default LoadOptions;

再调整select组件配置,传入初始分页参数、开启防抖优化体验:

import React, { useState } from "react";
import { AsyncPaginate } from "react-select-async-paginate";
import LoadOptions from "./LoadOptions";

const TooManySelect = () => {
  const [value, onChange] = useState(null);
  
  return (
    <div className="Select-options">
      <label>Pdt code</label>
      <AsyncPaginate
        defaultOptions
        value={value}
        loadOptions={LoadOptions}
        onChange={onChange}
        // 初始分页参数,首次加载从第0条开始
        additional={{
          offset: 0
        }}
        // 搜索防抖,避免输入过程中频繁发起请求
        debounceTimeout={300}
        // 距离菜单底部100px时提前触发下一页加载,滚动更流畅
        menuScrollThreshold={100}
      />
    </div>
  );
};

export default TooManySelect;
大数量场景卡顿优化

如果需要加载上万条选项,仅做分页还不够,累计渲染上千个DOM节点依然会卡顿,可以搭配以下优化:

  • 开启虚拟滚动:自定义MenuList组件,用虚拟滚动方案只渲染可视区域内的选项,哪怕全量加载2万条数据,页面也不会卡顿。
  • 优化后端分页查询:避免使用大偏移量的OFFSET语法,数据量越大OFFSET查询性能越差,可改为基于主键游标的分页(以上一次查询的最后一条记录ID作为下次查询的起始条件),查询速度能提升数倍。
  • 强化搜索能力:支持拼音、模糊匹配等搜索逻辑,引导用户通过输入关键词快速定位选项,减少滚动加载的数据量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 03:57:21