Industry News: server-render initial feed posts (fix 0 articles on load)
This commit is contained in:
@@ -53,13 +53,18 @@ function parseArticleDate(dateStr: string): Date | null {
|
||||
return isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
|
||||
export default function ArticleFeed() {
|
||||
type ArticleFeedProps = {
|
||||
initialPosts?: ArticleItem[];
|
||||
};
|
||||
|
||||
export default function ArticleFeed({ initialPosts = [] }: ArticleFeedProps) {
|
||||
const hasInitialPosts = initialPosts.length > 0;
|
||||
const [page, setPage] = useState(1);
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [activeCategory, setActiveCategory] = useState("All");
|
||||
const [sourceFilter, setSourceFilter] = useState<SourceFilter>("All");
|
||||
const [wpPosts, setWpPosts] = useState<ArticleItem[]>([]);
|
||||
const [loadingWp, setLoadingWp] = useState(true);
|
||||
const [wpPosts, setWpPosts] = useState<ArticleItem[]>(initialPosts);
|
||||
const [loadingWp, setLoadingWp] = useState(!hasInitialPosts);
|
||||
const [feedMode, setFeedMode] = useState<FeedMode>("pagination");
|
||||
const [infiniteCount, setInfiniteCount] = useState(ARTICLES_PER_PAGE);
|
||||
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
||||
@@ -89,8 +94,9 @@ export default function ArticleFeed() {
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Fetch imported WordPress posts for the feed
|
||||
// Client fetch only when the server did not hydrate initial posts.
|
||||
useEffect(() => {
|
||||
if (hasInitialPosts) return;
|
||||
let cancelled = false;
|
||||
(async () => {
|
||||
try {
|
||||
@@ -108,7 +114,7 @@ export default function ArticleFeed() {
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, []);
|
||||
}, [hasInitialPosts]);
|
||||
|
||||
const handleFeedModeChange = (mode: FeedMode) => {
|
||||
setFeedMode(mode);
|
||||
|
||||
@@ -8,6 +8,8 @@ import FeaturedCarouselServer from '@/components/FeaturedCarouselServer';
|
||||
import FeaturedBento from "./components/FeaturedBento";
|
||||
import SpotlightCarousel from "./components/SpotlightCarousel";
|
||||
import ArticleFeed from "./components/ArticleFeed";
|
||||
import { getLatestImportedArticles } from "@/lib/articles/legacy-source";
|
||||
import { decorateHomepageFeed } from "@/lib/promoted-articles";
|
||||
import ScrollRevealSection from "@/components/ScrollRevealSection";
|
||||
import NewsletterSignup from "./components/NewsletterSignup";
|
||||
import SponsorLogoStrip from "@/components/SponsorLogoStrip";
|
||||
@@ -137,7 +139,32 @@ function FeedSkeleton() {
|
||||
);
|
||||
}
|
||||
|
||||
export default function HomePage() {
|
||||
const HOME_FEED_LIMIT = 5000;
|
||||
|
||||
async function loadHomeFeedPosts() {
|
||||
const { items } = await getLatestImportedArticles(HOME_FEED_LIMIT, 0);
|
||||
const base = items.map((a) => ({
|
||||
title: a.title,
|
||||
excerpt: a.excerpt,
|
||||
category: a.category,
|
||||
date: a.date,
|
||||
author: a.author,
|
||||
authorSlug: a.authorSlug,
|
||||
slug: a.slug,
|
||||
image: a.image,
|
||||
alt: a.alt,
|
||||
source: "imported" as const,
|
||||
}));
|
||||
const decorated = await decorateHomepageFeed("avbeat", base);
|
||||
return decorated.map((d) => ({
|
||||
...d.article,
|
||||
promoted_kind: d.promoted_kind,
|
||||
promoted_advertiser: d.promoted_advertiser || null,
|
||||
promoted_until: d.promoted_until || null,
|
||||
}));
|
||||
}
|
||||
|
||||
export default async function HomePage() {
|
||||
// Hard opt-out of all caching for this route. Without this, a child
|
||||
// server component (FeaturedBentoFromDb -> pickAds -> fetch in lib/ads.ts
|
||||
// with `next: { revalidate: 30 }`) pulls the whole page into 30-second
|
||||
@@ -146,6 +173,7 @@ export default function HomePage() {
|
||||
// is the unambiguous, child-tree-overriding opt-out and is what the
|
||||
// hero swap needs to render fresh on every request.
|
||||
noStore();
|
||||
const initialFeedPosts = await loadHomeFeedPosts();
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
{/* Sticky top bar + nav */}
|
||||
@@ -174,7 +202,7 @@ export default function HomePage() {
|
||||
{/* Article feed + sidebar */}
|
||||
<ScrollRevealSection id="the-latest" className="section-enter section-enter-5 scroll-mt-32" delay={2}>
|
||||
<Suspense fallback={<FeedSkeleton />}>
|
||||
<ArticleFeed />
|
||||
<ArticleFeed initialPosts={initialFeedPosts} />
|
||||
</Suspense>
|
||||
</ScrollRevealSection>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user