mirror of
https://github.com/hamster1963/nezha-dash.git
synced 2025-04-24 21:10:45 +08:00
perf: refactor server data fetch
This commit is contained in:
parent
0c3479bb3b
commit
6b52a8dedb
@ -1,15 +1,15 @@
|
||||
"use client"
|
||||
|
||||
import { NezhaAPISafe, ServerApi } from "@/app/types/nezha-api"
|
||||
import { useServerData } from "@/app/lib/server-data-context"
|
||||
import { NezhaAPISafe } from "@/app/types/nezha-api"
|
||||
import { ServerDetailChartLoading } from "@/components/loading/ServerDetailLoading"
|
||||
import AnimatedCircularProgressBar from "@/components/ui/animated-circular-progress-bar"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { ChartConfig, ChartContainer } from "@/components/ui/chart"
|
||||
import { formatBytes, formatNezhaInfo, formatRelativeTime, nezhaFetcher } from "@/lib/utils"
|
||||
import { formatBytes, formatNezhaInfo, formatRelativeTime } from "@/lib/utils"
|
||||
import { useTranslations } from "next-intl"
|
||||
import { useEffect, useState } from "react"
|
||||
import { Area, AreaChart, CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts"
|
||||
import useSWRImmutable from "swr/immutable"
|
||||
|
||||
type cpuChartData = {
|
||||
timeStamp: string
|
||||
@ -52,16 +52,9 @@ export default function ServerDetailChartClient({
|
||||
}) {
|
||||
const t = useTranslations("ServerDetailChartClient")
|
||||
|
||||
const { data: allFallbackData } = useSWRImmutable<ServerApi>("/api/server", nezhaFetcher)
|
||||
const fallbackData = allFallbackData?.result?.find((item) => item.id === server_id)
|
||||
const { data: serverList, error } = useServerData()
|
||||
|
||||
const { data, error } = useSWRImmutable<NezhaAPISafe>(
|
||||
`/api/detail?server_id=${server_id}`,
|
||||
nezhaFetcher,
|
||||
{
|
||||
fallbackData,
|
||||
},
|
||||
)
|
||||
const data = serverList?.result?.find((item) => item.id === server_id)
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
|
@ -1,18 +1,15 @@
|
||||
"use client"
|
||||
|
||||
import { NezhaAPISafe, ServerApi } from "@/app/types/nezha-api"
|
||||
import { useServerData } from "@/app/lib/server-data-context"
|
||||
import { BackIcon } from "@/components/Icon"
|
||||
import ServerFlag from "@/components/ServerFlag"
|
||||
import { ServerDetailLoading } from "@/components/loading/ServerDetailLoading"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import getEnv from "@/lib/env-entry"
|
||||
import { cn, formatBytes, nezhaFetcher } from "@/lib/utils"
|
||||
import { cn, formatBytes } from "@/lib/utils"
|
||||
import { useTranslations } from "next-intl"
|
||||
import { notFound, useRouter } from "next/navigation"
|
||||
import { useEffect, useState } from "react"
|
||||
import useSWR from "swr"
|
||||
import useSWRImmutable from "swr/immutable"
|
||||
|
||||
export default function ServerDetailClient({ server_id }: { server_id: number }) {
|
||||
const t = useTranslations("ServerDetailClient")
|
||||
@ -39,24 +36,13 @@ export default function ServerDetailClient({ server_id }: { server_id: number })
|
||||
}
|
||||
}
|
||||
|
||||
const { data: allFallbackData, isLoading } = useSWRImmutable<ServerApi>(
|
||||
"/api/server",
|
||||
nezhaFetcher,
|
||||
)
|
||||
const fallbackData = allFallbackData?.result?.find((item) => item.id === server_id)
|
||||
const { data: serverList, error, isLoading } = useServerData()
|
||||
const data = serverList?.result?.find((item) => item.id === server_id)
|
||||
|
||||
if (!fallbackData && !isLoading) {
|
||||
if (!data && !isLoading) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
const { data, error } = useSWR<NezhaAPISafe>(`/api/detail?server_id=${server_id}`, nezhaFetcher, {
|
||||
refreshInterval: Number(getEnv("NEXT_PUBLIC_NezhaFetchInterval")) || 5000,
|
||||
dedupingInterval: 1000,
|
||||
fallbackData,
|
||||
revalidateOnMount: false,
|
||||
revalidateIfStale: false,
|
||||
})
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<>
|
||||
|
@ -1,8 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import { ServerApi } from "@/app/types/nezha-api"
|
||||
import { nezhaFetcher } from "@/lib/utils"
|
||||
import useSWRImmutable from "swr/immutable"
|
||||
import { useServerData } from "@/app/lib/server-data-context"
|
||||
|
||||
import GlobalLoading from "../../../../components/loading/GlobalLoading"
|
||||
import { geoJsonString } from "../../../../lib/geo-json-string"
|
||||
@ -11,7 +9,7 @@ import GlobalInfo from "./GlobalInfo"
|
||||
import { InteractiveMap } from "./InteractiveMap"
|
||||
|
||||
export default function ServerGlobal() {
|
||||
const { data: nezhaServerList, error } = useSWRImmutable<ServerApi>("/api/server", nezhaFetcher)
|
||||
const { data: nezhaServerList, error } = useServerData()
|
||||
|
||||
if (error)
|
||||
return (
|
||||
|
@ -1,18 +1,17 @@
|
||||
"use client"
|
||||
|
||||
import { ServerApi } from "@/app/types/nezha-api"
|
||||
import { useServerData } from "@/app/lib/server-data-context"
|
||||
import ServerCard from "@/components/ServerCard"
|
||||
import ServerCardInline from "@/components/ServerCardInline"
|
||||
import Switch from "@/components/Switch"
|
||||
import getEnv from "@/lib/env-entry"
|
||||
import { useFilter } from "@/lib/network-filter-context"
|
||||
import { useStatus } from "@/lib/status-context"
|
||||
import { cn, nezhaFetcher } from "@/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { MapIcon, ViewColumnsIcon } from "@heroicons/react/20/solid"
|
||||
import { useTranslations } from "next-intl"
|
||||
import dynamic from "next/dynamic"
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
import useSWR from "swr"
|
||||
|
||||
import GlobalLoading from "../../../../components/loading/GlobalLoading"
|
||||
|
||||
@ -70,10 +69,7 @@ export default function ServerListClient() {
|
||||
}
|
||||
}, [])
|
||||
|
||||
const { data, error } = useSWR<ServerApi>("/api/server", nezhaFetcher, {
|
||||
refreshInterval: Number(getEnv("NEXT_PUBLIC_NezhaFetchInterval")) || 2000,
|
||||
dedupingInterval: 1000,
|
||||
})
|
||||
const { data, error } = useServerData()
|
||||
|
||||
if (error)
|
||||
return (
|
||||
|
@ -1,31 +1,30 @@
|
||||
"use client"
|
||||
|
||||
import { ServerApi } from "@/app/types/nezha-api"
|
||||
import { useServerData } from "@/app/lib/server-data-context"
|
||||
import { Loader } from "@/components/loading/Loader"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import getEnv from "@/lib/env-entry"
|
||||
import { useFilter } from "@/lib/network-filter-context"
|
||||
import { useStatus } from "@/lib/status-context"
|
||||
import { cn, formatBytes, nezhaFetcher } from "@/lib/utils"
|
||||
import { cn, formatBytes } from "@/lib/utils"
|
||||
import blogMan from "@/public/blog-man.webp"
|
||||
import { ArrowDownCircleIcon, ArrowUpCircleIcon } from "@heroicons/react/20/solid"
|
||||
import { useTranslations } from "next-intl"
|
||||
import Image from "next/image"
|
||||
import useSWRImmutable from "swr/immutable"
|
||||
|
||||
export default function ServerOverviewClient() {
|
||||
const { data, error, isLoading } = useServerData()
|
||||
const { status, setStatus } = useStatus()
|
||||
const { filter, setFilter } = useFilter()
|
||||
const t = useTranslations("ServerOverviewClient")
|
||||
|
||||
const { data, error, isLoading } = useSWRImmutable<ServerApi>("/api/server", nezhaFetcher)
|
||||
const disableCartoon = getEnv("NEXT_PUBLIC_DisableCartoon") === "true"
|
||||
|
||||
if (error) {
|
||||
const errorInfo = error as any
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<p className="text-sm font-medium opacity-40">
|
||||
Error status:{error.status} {error.info?.cause ?? error.message}
|
||||
Error status:{errorInfo?.status} {errorInfo.info?.cause ?? errorInfo?.message}
|
||||
</p>
|
||||
<p className="text-sm font-medium opacity-40">{t("error_message")}</p>
|
||||
</div>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import Footer from "@/app/(main)/footer"
|
||||
import Header from "@/app/(main)/header"
|
||||
import { ServerDataProvider } from "@/app/lib/server-data-context"
|
||||
import { auth } from "@/auth"
|
||||
import { SignIn } from "@/components/SignIn"
|
||||
import getEnv from "@/lib/env-entry"
|
||||
@ -13,7 +14,9 @@ export default function MainLayout({ children }: DashboardProps) {
|
||||
<div className="flex min-h-screen w-full flex-col">
|
||||
<main className="flex min-h-[calc(100vh-calc(var(--spacing)*16))] flex-1 flex-col gap-4 bg-background p-4 md:p-10 md:pt-8">
|
||||
<Header />
|
||||
<AuthProtected>{children}</AuthProtected>
|
||||
<AuthProtected>
|
||||
<ServerDataProvider>{children}</ServerDataProvider>
|
||||
</AuthProtected>
|
||||
<Footer />
|
||||
</main>
|
||||
</div>
|
||||
|
62
app/lib/server-data-context.tsx
Normal file
62
app/lib/server-data-context.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
"use client"
|
||||
|
||||
import { ServerApi } from "@/app/types/nezha-api"
|
||||
import getEnv from "@/lib/env-entry"
|
||||
import { nezhaFetcher } from "@/lib/utils"
|
||||
import { ReactNode, createContext, useContext, useEffect, useState } from "react"
|
||||
import useSWR from "swr"
|
||||
|
||||
interface ServerDataWithTimestamp {
|
||||
timestamp: number
|
||||
data: ServerApi
|
||||
}
|
||||
|
||||
interface ServerDataContextType {
|
||||
data: ServerApi | undefined
|
||||
error: Error | undefined
|
||||
isLoading: boolean
|
||||
history: ServerDataWithTimestamp[]
|
||||
}
|
||||
|
||||
const ServerDataContext = createContext<ServerDataContextType | undefined>(undefined)
|
||||
|
||||
const MAX_HISTORY_LENGTH = 30
|
||||
|
||||
export function ServerDataProvider({ children }: { children: ReactNode }) {
|
||||
const [history, setHistory] = useState<ServerDataWithTimestamp[]>([])
|
||||
|
||||
const { data, error, isLoading } = useSWR<ServerApi>("/api/server", nezhaFetcher, {
|
||||
refreshInterval: Number(getEnv("NEXT_PUBLIC_NezhaFetchInterval")) || 2000,
|
||||
dedupingInterval: 1000,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
setHistory((prev) => {
|
||||
const newHistory = [
|
||||
{
|
||||
timestamp: Date.now(),
|
||||
data: data,
|
||||
},
|
||||
...prev,
|
||||
].slice(0, MAX_HISTORY_LENGTH)
|
||||
|
||||
return newHistory
|
||||
})
|
||||
}
|
||||
}, [data])
|
||||
|
||||
return (
|
||||
<ServerDataContext.Provider value={{ data, error, isLoading, history }}>
|
||||
{children}
|
||||
</ServerDataContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useServerData() {
|
||||
const context = useContext(ServerDataContext)
|
||||
if (context === undefined) {
|
||||
throw new Error("useServerData must be used within a ServerDataProvider")
|
||||
}
|
||||
return context
|
||||
}
|
Loading…
Reference in New Issue
Block a user