React中双日期区间渲染对象列表遇无限循环的专业解决方案
解决React日期过滤演唱会列表的无限循环问题
你的代码出现无限循环的核心原因是在组件渲染的顶层直接调用了setConcerts(filtered)。每次组件渲染时,这个状态更新函数都会执行,触发组件重新渲染,而重新渲染又会再次执行这个函数,形成无限循环。
此外还有两个潜在问题:
- 直接修改原始
concerts状态会覆盖加载回来的完整数据,导致后续无法基于全量数据重新过滤 - 当前加载状态判断逻辑有误:初始
concerts为空数组时,filtered.length也会是0,会一直显示Loading,但实际可能已经加载完成只是没有匹配数据
正确实现思路
- 保留原始演唱会数据状态,过滤结果作为派生状态在渲染时计算(或用
useMemo优化性能) - 移除顶层的
setConcerts(filtered)调用,避免触发不必要的状态更新 - 新增加载状态变量,明确区分「正在加载」和「加载完成但无匹配数据」的场景
修改后的完整代码
import React from "react"; import axios from "axios"; import { useState, useEffect, useMemo } from "react"; const Explore = () => { // Raw JSON Date example: "2023-02-08T23:15:30.000Z" const currentDate = new Date().toJSON().slice(0, 10); const [concerts, setConcerts] = useState([]); const [startDate, setStartDate] = useState(currentDate); const [endDate, setEndDate] = useState(currentDate); const [isLoading, setIsLoading] = useState(true); // 新增加载状态 useEffect(() => { const loadConcerts = async () => { try { const request = await axios.get("data/concerts"); setConcerts(request.data); } catch (err) { console.error("加载演唱会数据失败:", err); } finally { setIsLoading(false); // 无论成功失败都结束加载状态 } }; loadConcerts(); }, []); // 使用useMemo缓存过滤结果,仅当依赖项变化时重新计算 const filteredConcerts = useMemo(() => { return concerts.filter((concert) => { // 提取演唱会日期的YYYY-MM-DD部分,和选择的纯日期字符串匹配比较 const concertDate = concert.datum.slice(0, 10); return concertDate >= startDate && concertDate <= endDate; }); }, [concerts, startDate, endDate]); if (isLoading) { return <h1>Loading</h1>; } return ( <div> <label htmlFor="start">Start date:</label> <label htmlFor="end">End date:</label> <input type="date" id="start" value={startDate} min="2023-01-01" max="2030-12-31" onChange={(event) => setStartDate(event.target.value)} /> <input type="date" id="end" value={endDate} min="2023-01-01" max="2030-12-31" onChange={(event) => setEndDate(event.target.value)} /> <div> {filteredConcerts.length === 0 ? ( <p>该日期范围内没有演唱会</p> ) : ( /* 这里渲染你的演唱会卡片,示例: filteredConcerts.map(concert => ( <ConcertCard key={concert.id} {...concert} /> )) */ <div>渲染演唱会卡片区域</div> )} </div> </div> ); }; export default Explore;
关键修改点说明
- 移除顶层状态更新:删掉
setConcerts(filtered),不再修改原始数据状态,彻底切断无限循环的触发源 - 新增加载状态:用
isLoading变量明确标记加载阶段,解决初始空数组误判为加载中的问题 - useMemo优化过滤:仅在
concerts、startDate或endDate变化时重新计算过滤结果,避免无意义的重复计算 - 修正日期比较逻辑:提取演唱会日期的纯日期部分再比较,确保带时间的ISO字符串和选择的日期匹配准确
内容的提问来源于stack exchange,提问作者lbs91
相关产品推荐
相关产品推荐

