Fix: eliminate reload-only hydration mismatches on home

Make HomePage a server component and mount ActivityFeed via a client-only wrapper to avoid Suspense/dynamic boundary differences between SSR and hydration.
This commit is contained in:
Cursor Agent
2026-01-14 10:45:34 +00:00
parent 4f344ff1de
commit 1d2c8cee09
2 changed files with 36 additions and 36 deletions

View File

@@ -0,0 +1,31 @@
"use client";
import React, { useEffect, useState } from "react";
type ActivityFeedComponent = React.ComponentType<Record<string, never>>;
export default function ActivityFeedClient() {
const [Comp, setComp] = useState<ActivityFeedComponent | null>(null);
useEffect(() => {
let cancelled = false;
(async () => {
try {
const mod = await import("../components/ActivityFeed");
const C = (mod as unknown as { default?: ActivityFeedComponent }).default;
if (!cancelled && typeof C === "function") {
setComp(() => C);
}
} catch {
// ignore
}
})();
return () => {
cancelled = true;
};
}, []);
if (!Comp) return null;
return <Comp />;
}

View File

@@ -1,5 +1,3 @@
"use client";
import Header from "../components/Header";
import Hero from "../components/Hero";
import About from "../components/About";
@@ -7,19 +5,7 @@ import Projects from "../components/Projects";
import Contact from "../components/Contact";
import Footer from "../components/Footer";
import Script from "next/script";
import dynamic from "next/dynamic";
import ErrorBoundary from "@/components/ErrorBoundary";
import { motion } from "framer-motion";
// Wrap ActivityFeed in error boundary to prevent crashes
const ActivityFeed = dynamic(
() =>
import("../components/ActivityFeed").catch(() => ({ default: () => null })),
{
ssr: false,
loading: () => null,
},
);
import ActivityFeedClient from "./ActivityFeedClient";
export default function HomePage() {
return (
@@ -46,9 +32,7 @@ export default function HomePage() {
}),
}}
/>
<ErrorBoundary>
<ActivityFeed />
</ErrorBoundary>
<ActivityFeedClient />
<Header />
{/* Spacer to prevent navbar overlap */}
<div className="h-24 md:h-32" aria-hidden="true"></div>
@@ -62,14 +46,9 @@ export default function HomePage() {
viewBox="0 0 1440 120"
preserveAspectRatio="none"
>
<motion.path
<path
d="M0,64 C240,96 480,32 720,64 C960,96 1200,32 1440,64 L1440,120 L0,120 Z"
fill="url(#gradient1)"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{
opacity: { duration: 0.8, delay: 0.3 },
}}
/>
<defs>
<linearGradient id="gradient1" x1="0%" y1="0%" x2="100%" y2="0%">
@@ -90,14 +69,9 @@ export default function HomePage() {
viewBox="0 0 1440 120"
preserveAspectRatio="none"
>
<motion.path
<path
d="M0,32 C240,64 480,96 720,32 C960,64 1200,96 1440,32 L1440,120 L0,120 Z"
fill="url(#gradient2)"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{
opacity: { duration: 0.8, delay: 0.3 },
}}
/>
<defs>
<linearGradient id="gradient2" x1="0%" y1="0%" x2="100%" y2="0%">
@@ -118,14 +92,9 @@ export default function HomePage() {
viewBox="0 0 1440 120"
preserveAspectRatio="none"
>
<motion.path
<path
d="M0,96 C240,32 480,64 720,96 C960,32 1200,64 1440,96 L1440,120 L0,120 Z"
fill="url(#gradient3)"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{
opacity: { duration: 0.8, delay: 0.3 },
}}
/>
<defs>
<linearGradient id="gradient3" x1="0%" y1="0%" x2="100%" y2="0%">