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

如何创建可通过按钮点击筛选的Firestore数据表格?

解决Firestore数据筛选表格的无限循环问题

问题根源

你的代码陷入无限循环的核心原因是按钮的onClick属性错误地直接调用了函数:

<button onClick={handleUpcoming()}>Upcoming</button>
<button onClick={handlePast()}>Past</button>

这种写法会导致组件每次渲染时立即执行handleUpcoming和handlePast,调用setAccounts更新状态后触发组件重渲染,进而再次执行这两个函数,形成无限循环。

另外还有两个可优化点:

  • currentDate在组件每次渲染时都会重新计算,建议用useMemo缓存
  • 列表渲染的<tr>缺少key属性,会触发React性能警告

修改后的完整代码

import React, { useState, useMemo, useEffect } from 'react';
import './App.css';
import db from './firebase';
import 'react-toastify/dist/ReactToastify.css';

const App = () => {
  // 用useMemo缓存当前日期,避免每次渲染重复计算
  const currentDate = useMemo(() => new Date().toISOString().slice(0, 10), []);
  const [accounts, setAccounts] = useState([]);

  // 获取即将到来的预约
  const handleUpcoming = async () => {
    const response = db.collection('accounts').where('schedule', '>', currentDate);
    const data = await response.get();
    const newAccounts = data.docs.map(item => ({...item.data(), id: item.id})) // 添加id作为key
    setAccounts(newAccounts);
  }

  // 获取已过去的预约
  const handlePast = async () => {
    const response = db.collection('accounts').where('schedule', '<', currentDate);
    const data = await response.get();
    const newAccounts = data.docs.map(item => ({...item.data(), id: item.id})) // 添加id作为key
    setAccounts(newAccounts);
  }

  // 组件挂载时默认加载所有预约(可选,根据需求调整)
  useEffect(() => {
    const fetchAllAccounts = async () => {
      const response = db.collection('accounts');
      const data = await response.get();
      const newAccounts = data.docs.map(item => ({...item.data(), id: item.id}))
      setAccounts(newAccounts);
    };
    fetchAllAccounts();
  }, []);

  return (
    <div className="app-container">
      <h1>Appointments</h1>
      <div className="button-container">
        {/* 传递函数引用,而非立即执行 */}
        <button onClick={handleUpcoming}>Upcoming</button>
        <button onClick={handlePast}>Past</button>
        <div className="scrollbar">
          <table>
            <thead>
              {/* 可选:添加表头 */}
              <tr>
                <th>Name & Email</th>
                <th>Schedule</th>
                <th>Service</th>
                <th>Mobile Number</th>
              </tr>
            </thead>
            <tbody>
              {accounts.map(account => (
                // 添加唯一key属性
                <tr key={account.id}>
                  <td className="appointmentDataOne">
                    {account.name}
                    <div className="appointmentDataTwo">{account.email}</div>
                  </td>
                  <td className="appointmentDataOne">{account.schedule}</td>
                  <td className="appointmentDataTwo">{account.service}</td>
                  <td className="appointmentDataTwo">{account.mobileNumber}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

export default App;

关键修改说明

  1. 修复无限循环:将按钮的onClick={handleUpcoming()}改为onClick={handleUpcoming},传递函数引用而非立即执行,只有点击按钮时才会触发函数。
  2. 缓存当前日期:用useMemo缓存currentDate,确保组件重新渲染时不会重复生成日期字符串。
  3. 添加列表key:在映射accounts时,将Firestore文档的id添加到数据中,作为<tr>的key属性,符合React列表渲染规范,避免性能警告。
  4. 初始数据加载(可选):通过useEffect在组件挂载时默认加载所有预约数据,提升用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 23:55:18