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

ReactJS中如何实现多筛选条件下点击按钮切换展示表格数据

React 多筛选条件表格切换实现方案

需求说明

主页表格需要支持多维度筛选切换,交互规则如下:

  • 用户首次进入页面时,表格默认展示分页加载的currentUserData
  • 点击「Today」按钮,表格展示当日筛选结果todayData
  • 点击「This Week」按钮,表格展示当周筛选结果thisWeekData
  • 点击「This Month」按钮,表格展示当月筛选结果thisMonthData
  • 点击「Custom」按钮,表格展示自定义日期区间筛选结果customData
  • 点击「Today」板块下拉菜单中的用户选项,表格展示对应用户的筛选结果dropDownUserData

关联数据定义

  • userData:数据库存储的全量原始业务数据
  • todayData:从全量数据中筛选出的当日数据,点击Today按钮时触发筛选/加载
  • thisWeekData:从全量数据中筛选出的当周数据,点击This Week按钮时触发筛选/加载
  • thisMonthData:从全量数据中筛选出的当月数据,点击This Month按钮时触发筛选/加载
  • customData:从全量数据中筛选出的自定义日期区间数据,点击Custom按钮选择完日期范围后触发筛选/加载
  • dropDownUserData:从全量数据中筛选出的下拉菜单选中用户的对应数据,点击下拉用户选项时触发筛选/加载
  • currentUserData:默认分页加载的用户列表数据,支持根据searchInput做用户名模糊匹配搜索

原有代码问题

现有实现通过多层嵌套三元运算符,判断各数据集的长度来决定渲染内容,存在三个核心问题:

  1. 交互逻辑完全失效:只要优先级高的数据集(比如todayData)不为空,无论用户点击哪个筛选按钮,都只会展示优先级最高的数据集内容,根本不会响应用户的切换操作
  2. 代码冗余度极高:同一段表格行渲染逻辑重复写了6遍,后续改字段、调样式需要改6处,维护成本极高
  3. 细节不规范:直接在<tbody>标签下渲染Loading文本不符合HTML表格嵌套规则,会导致布局错乱;filter回调返回数据项而非布尔值,写法不严谨。

原有实现代码如下:

<tbody>
{

  // 👇️判断当日数据是否存在,存在则渲染
   todayData.length > 0 ?

    todayData.map((user, id) =>
      <tr key={id} className='table-row'>
        <td className='table-item'>{user.date}</td>
        <td className='table-item'>{user.from}</td>
        <td className='table-item'>{user.to}</td>
        <td className='table-item'>{user.duration}</td>
        <td className='table-item'>{user.hangup}</td>
        <td className='table-item'>{user.action}</td>
      </tr>)

    :

    // 👇️判断当周数据是否存在,存在则渲染
    thisWeekData.length > 0 ?

      thisWeekData.map((user, id) =>
        <tr key={id} className='table-row'>
          <td className='table-item'>{user.date}</td>
          <td className='table-item'>{user.from}</td>
          <td className='table-item'>{user.to}</td>
          <td className='table-item'>{user.duration}</td>
          <td className='table-item'>{user.hangup}</td>
          <td className='table-item'>{user.action}</td>
        </tr>
      )

      :

      // 👇️判断当月数据是否存在,存在则渲染
      thisMonthData.length > 0 ?

        thisMonthData.map((user, id) =>
          <tr key={id} className='table-row'>
            <td className='table-item'>{user.date}</td>
            <td className='table-item'>{user.from}</td>
            <td className='table-item'>{user.to}</td>
            <td className='table-item'>{user.duration}</td>
            <td className='table-item'>{user.hangup}</td>
            <td className='table-item'>{user.action}</td>
          </tr>
        )

        :

        // 👇️判断自定义日期筛选数据是否存在,存在则渲染
        customData.length > 0 ?

          customData.map((user, id) =>
            <tr key={id} className='table-row'>
              <td className='table-item'>{user.date}</td>
              <td className='table-item'>{user.from}</td>
              <td className='table-item'>{user.to}</td>
              <td className='table-item'>{user.duration}</td>
              <td className='table-item'>{user.hangup}</td>
              <td className='table-item'>{user.action}</td>
            </tr>
          )

          :

          // 👇️判断下拉用户选中数据是否存在,存在则渲染
          dropDownUserData ?

            dropDownUserData.map((user, id) =>
              <tr key={id} className='table-row'>
                <td className='table-item'>{user.date}</td>
                <td className='table-item'>{user.from}</td>
                <td className='table-item'>{user.to}</td>
                <td className='table-item'>{user.duration}</td>
                <td className='table-item'>{user.hangup}</td>
                <td className='table-item'>{user.action}</td>
              </tr>
            )

            :

            // 👇️判断分页数据是否存在,存在则走搜索逻辑后渲染,否则展示Loading
            currentUserData && currentUserData.length > 0 ?
              currentUserData.filter((value) => {
                if (searchInput === '') {
                  return value
                }
                else if (value.name.toLowerCase().includes(searchInput.toLowerCase())) {
                  return value
                }
              })
              .map((user, id) =>
                <tr key={id} className='table-row'>
                  <td className='table-item'>{user.date}</td>
                  <td className='table-item'>{user.from}</td>
                  <td className='table-item'>{user.to}</td>
                  <td className='table-item'>{user.duration}</td>
                  <td className='table-item'>{user.hangup}</td>
                  <td className='table-item'>{user.action}</td>
                </tr>
              ) : 'Loading'

}
</tbody>

优化实现方案

核心思路是新增状态记录当前激活的筛选类型,用户点击对应筛选入口时更新这个状态,渲染时直接根据激活状态匹配对应数据源即可,同时抽离公共的表格行渲染逻辑消除重复代码。

  1. 首先定义筛选类型枚举和激活状态,默认值设为默认分页,满足首次加载展示currentUserData的需求:
// 筛选类型枚举,避免硬编码写错
const FILTER_TYPES = {
  DEFAULT: 'default',
  TODAY: 'today',
  THIS_WEEK: 'thisWeek',
  THIS_MONTH: 'thisMonth',
  CUSTOM: 'custom',
  DROPDOWN_USER: 'dropdownUser'
}

// 组件内声明状态
const [activeFilter, setActiveFilter] = useState(FILTER_TYPES.DEFAULT)
  1. 给所有筛选交互入口绑定状态更新逻辑,点击时切换激活的筛选类型:
// Today按钮点击事件
const handleTodayClick = () => {
  // 如果数据没有预加载,可以在这里加请求/筛选todayData的逻辑
  setActiveFilter(FILTER_TYPES.TODAY)
}
// This Week按钮点击事件
const handleWeekClick = () => {
  setActiveFilter(FILTER_TYPES.THIS_WEEK)
}
// This Month按钮点击事件
const handleMonthClick = () => {
  setActiveFilter(FILTER_TYPES.THIS_MONTH)
}
// Custom按钮确认事件
const handleCustomFilterSet = () => {
  // 日期选择完成、customData生成后调用
  setActiveFilter(FILTER_TYPES.CUSTOM)
}
// 下拉菜单用户选中事件
const handleUserSelect = () => {
  // 选中用户、dropDownUserData生成后调用
  setActiveFilter(FILTER_TYPES.DROPDOWN_USER)
}
  1. 抽离公共的表格行渲染方法,统一处理搜索过滤、空态/加载态展示:
const renderTableRows = (dataSource) => {
  // 只有默认分页数据需要走用户名搜索过滤
  const displayData = activeFilter === FILTER_TYPES.DEFAULT
    ? dataSource?.filter(item => {
        const keyword = searchInput.trim().toLowerCase()
        if(!keyword) return true
        return item.name.toLowerCase().includes(keyword)
      })
    : dataSource

  // 数据未加载/为空时展示Loading,套在跨列单元格里避免布局错乱
  if(!displayData || displayData.length === 0) {
    return (
      <tr>
        <td colSpan={6} className="table-loading">Loading</td>
      </tr>
    )
  }

  return displayData.map((user, id) => (
    <tr key={id} className='table-row'>
      <td className='table-item'>{user.date}</td>
      <td className='table-item'>{user.from}</td>
      <td className='table-item'>{user.to}</td>
      <td className='table-item'>{user.duration}</td>
      <td className='table-item'>{user.hangup}</td>
      <td className='table-item'>{user.action}</td>
    </tr>
  ))
}
  1. 简化表格主体渲染逻辑,根据当前激活的筛选类型传入对应数据源即可,完全去掉嵌套三元:
<tbody>
  {
    (() => {
      switch(activeFilter) {
        case FILTER_TYPES.TODAY:
          return renderTableRows(todayData)
        case FILTER_TYPES.THIS_WEEK:
          return renderTableRows(thisWeekData)
        case FILTER_TYPES.THIS_MONTH:
          return renderTableRows(thisMonthData)
        case FILTER_TYPES.CUSTOM:
          return renderTableRows(customData)
        case FILTER_TYPES.DROPDOWN_USER:
          return renderTableRows(dropDownUserData)
        case FILTER_TYPES.DEFAULT:
        default:
          return renderTableRows(currentUserData)
      }
    })()
  }
</tbody>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 03:54:20