修复温度走势图不显示:移除 IntersectionObserver 延迟渲染
问题:图表只在 IntersectionObserver 检测到视口交叉后才渲染 - 卡片折叠时图表区域永远不可见,IntersectionObserver 不触发 - 小屏幕/快速滚动时图表可能来不及渲染 修复: - 移除 IntersectionObserver 懒加载逻辑 - 图表始终立即渲染(useChart 在挂载时初始化) - Chart.js animation:false 确保快速渲染,无性能代价 - 清理未使用的 useState/useEffect 导入
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import type { ChartConfiguration } from "chart.js";
|
import type { ChartConfiguration } from "chart.js";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useMemo, useRef } from "react";
|
||||||
import { BarChart3 } from "lucide-react";
|
import { BarChart3 } from "lucide-react";
|
||||||
import type { CityDetail } from "@/lib/dashboard-types";
|
import type { CityDetail } from "@/lib/dashboard-types";
|
||||||
import { useChart } from "@/hooks/useChart";
|
import { useChart } from "@/hooks/useChart";
|
||||||
@@ -64,15 +64,14 @@ function buildTemperatureChartSignature(detail: CityDetail) {
|
|||||||
export function AiCityTemperatureChart({ detail }: { detail: CityDetail }) {
|
export function AiCityTemperatureChart({ detail }: { detail: CityDetail }) {
|
||||||
const { locale } = useI18n();
|
const { locale } = useI18n();
|
||||||
const sectionRef = useRef<HTMLElement | null>(null);
|
const sectionRef = useRef<HTMLElement | null>(null);
|
||||||
const [shouldRenderChart, setShouldRenderChart] = useState(false);
|
|
||||||
const cityKey = `${detail.name || detail.display_name || ""}:${detail.local_date || ""}`;
|
const cityKey = `${detail.name || detail.display_name || ""}:${detail.local_date || ""}`;
|
||||||
const chartSignature = useMemo(
|
const chartSignature = useMemo(
|
||||||
() => (shouldRenderChart ? buildTemperatureChartSignature(detail) : ""),
|
() => buildTemperatureChartSignature(detail),
|
||||||
[detail, shouldRenderChart],
|
[detail],
|
||||||
);
|
);
|
||||||
const computedChartData = useMemo(
|
const computedChartData = useMemo(
|
||||||
() => (shouldRenderChart ? getTemperatureChartData(detail, locale) : null),
|
() => getTemperatureChartData(detail, locale),
|
||||||
[chartSignature, detail, locale, shouldRenderChart],
|
[chartSignature, detail, locale],
|
||||||
);
|
);
|
||||||
const lastChartDataRef = useRef<{
|
const lastChartDataRef = useRef<{
|
||||||
cityKey: string;
|
cityKey: string;
|
||||||
@@ -233,26 +232,6 @@ export function AiCityTemperatureChart({ detail }: { detail: CityDetail }) {
|
|||||||
observationLabel,
|
observationLabel,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (shouldRenderChart) return;
|
|
||||||
if (typeof window === "undefined" || !("IntersectionObserver" in window)) {
|
|
||||||
setShouldRenderChart(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const target = sectionRef.current;
|
|
||||||
if (!target) return;
|
|
||||||
const observer = new IntersectionObserver(
|
|
||||||
(entries) => {
|
|
||||||
if (!entries.some((entry) => entry.isIntersecting)) return;
|
|
||||||
setShouldRenderChart(true);
|
|
||||||
observer.disconnect();
|
|
||||||
},
|
|
||||||
{ rootMargin: "220px 0px" },
|
|
||||||
);
|
|
||||||
observer.observe(target);
|
|
||||||
return () => observer.disconnect();
|
|
||||||
}, [shouldRenderChart]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="scan-ai-city-section chart" ref={sectionRef}>
|
<section className="scan-ai-city-section chart" ref={sectionRef}>
|
||||||
<div className="scan-ai-city-section-title">
|
<div className="scan-ai-city-section-title">
|
||||||
@@ -260,13 +239,7 @@ export function AiCityTemperatureChart({ detail }: { detail: CityDetail }) {
|
|||||||
<span>{locale === "en-US" ? "Evidence · intraday path" : "证据 · 今日日内路径"}</span>
|
<span>{locale === "en-US" ? "Evidence · intraday path" : "证据 · 今日日内路径"}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="scan-ai-city-chart">
|
<div className="scan-ai-city-chart">
|
||||||
{shouldRenderChart ? (
|
<canvas ref={canvasRef} />
|
||||||
<canvas ref={canvasRef} />
|
|
||||||
) : (
|
|
||||||
<div className="scan-ai-city-chart-placeholder">
|
|
||||||
{locale === "en-US" ? "Chart will render when visible" : "图表进入视口后再渲染"}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{chartData ? (
|
{chartData ? (
|
||||||
<div className="scan-ai-city-chart-legend">
|
<div className="scan-ai-city-chart-legend">
|
||||||
|
|||||||
Reference in New Issue
Block a user