**页面.jsx **
"use client"
import React, { useState, useEffect } from 'react';
import PostCard from '@/components/PostCard/page';
import { BASE_API_URL } from '@/utils/constants';
const Home = () => {
const [blogs, setBlogs] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
const fetchPosts = async () =>
{
setIsLoading(true);
try {
const res = await fetch(`${process.env.NEXT_PUBLIC_BASE_API_URL}/api/posts`,{
cache:"no-store",
});
if (!res.ok) {
throw new Error('Failed to fetch posts');
}
const data = await res.json();
setBlogs(data);
} catch (error) {
setError(error);
} finally {
setIsLoading(false);
}
};
fetchPosts();
}, []);
return (
<div className='container mx-auto border-rose-500 flex flex-col gap-4 flex-wrap justify-center w-5/6 md:w-3/6'>
<div className='flex flex-col'>
<div>
<h1 className='text-3xl md:text-5xl font-bold mb-8 text-white'>My Blogs</h1>
</div>
{isLoading && <div className="loader">Loading...</div>}
{error && <div className="error">{error.message}</div>}
{blogs.length > 0 && (
<div className="flex flex-col gap-2 mb-8 w-full">
{blogs.map((post) => (
<PostCard data={post} key={post._id} />
))}
</div>
)}
{!isLoading && !error && blogs.length === 0 && (
<div className="empty-state">No posts found.</div>
)}
</div>
</div>
);
};
export default Home;
postDesc/[slug].jsx:
import { BASE_API_URL } from "@/utils/constants";
import React from "react";
import Markdown from 'react-markdown';
import Image from 'next/image';
async function getPostById(slug) {
const res = await fetch(`${process.env.NEXT_PUBLIC_BASE_API_URL}/api/posts/${slug}`, {
cache: "no-store",
});
if (!res.ok) {
throw new Error("Fetching Post Failed!");
}
return res.json();
}
const PostDetail = async ({ params }) => {
const post = await getPostById(params.slug);
const formatDateString = (dateString) => {
const dateObject = new Date(dateString);
const options = { day: "2-digit", month: "long", year: "2-digit" };
return dateObject.toLocaleDateString("en-GB", options).replace(/\//g, " ");
};
const handleImageTag = (domNode) => {
if (domNode.type === 'tag' && domNode.name === 'img') {
// Customize styling for the img tag
return <Image {...domNode.attribs} alt="img" className="w-full h-80 object-center my-4" width={0}
height={0}
sizes="100vw"
style={{ width: '100%', height: "320px" }} />;
}
return null;
};
const options = {
replace: handleImageTag,
};
return (
<div class="max-w-screen-lg mx-auto mb-8 md:w-3/6">
<main>
<div class="mb-4 md:mb-0 w-full mx-auto relative">
<Image
alt="img"
src={post.img}
width={0}
height={0}
sizes="100vw"
style={{ width: '100%', height: "320px" }}
className="transition-opacity ease-in duration-700 opacity-80 w-full h-96 object-cover lg:rounded p-4 md:p-0"
/>
</div>
<div className="flex flex-col items-center mt-8">
<h2 class="text-3xl text-center md:text-normal md:text-5xl font-semibold text-white leading-tight mb-4 px-2">
{post.title}
</h2>
<div className="flex items-center gap-4 m-2">
<div>
<Image
alt="img"
src={post.img}
width={0}
height={0}
sizes="100vw"
style={{ width: '30px', height: "30px" }}// Choose the appropriate layout based on your needs
className="object-cover rounded p-4 md:p-0"
/>
</div>
<p className="text-sm">{post.author}</p>
<p className="text-txt text-sm">
{formatDateString(post.createdAt)}
</p>
</div>
</div>
<div></div>
<div className="content mx-auto flex flex-col lg:flex-row md:mt-2 flex-wrap md:p-4 w-fit">
<div className="px-4 lg:px-0 text-white flex-wrap text-lg leading-relaxed w-full text-justify text-txt tracking-tight font-primary">
{
<Markdown>{post.content}</Markdown>
}
</div>
</div>
</main>
</div>
);
};
export default PostDetail;
我有两个API路线
import connection from '@/utils/dbConnect';
import Post from '@/models/Posts';
import { NextResponse } from "next/server";
export const GET = async(request)=>
{
try{
await connection();
const posts = await Post.find()
return new NextResponse(JSON.stringify(posts), {status: 200, headers: { 'Cache-Control': 'no-store' }});
}catch(error){
console.log(error);
return new NextResponse("Database Error", {status: 400, headers: { 'Cache-Control': 'no-store' }});
}
}
import connection from '@/utils/dbConnect';
import Post from '@/models/Posts';
import { NextResponse } from "next/server"
export const GET = async(request, {params})=>{
const {slug} = params
// fetch data
try{
await connection();
const post = await Post.findOne({slug: slug});
return new NextResponse(JSON.stringify(post), {status: 200, headers: { 'Cache-Control': 'no-store' }})
}
catch(err){
return new NextResponse("Database Error", {status: 500, headers: { 'Cache-Control': 'no-store' }})
}
}
我有这两个我使用的网址:
NEXT_PUBLIC_BASE_API_URL=https://app-name.vercel.app (this does not fetch new posts)
NEXT_PUBLIC_BASE_API_URL=http://localhost:3000
当我在 API 中使用本地主机 URL 访问数据库并获取帖子时,它会返回所有新帖子和更新,但是当我使用部署的 URL(.vercel 一个)时,我会获取缓存的数据,并且不会返回新的帖子和更新。数据已获取。
我想你已经认识到这个问题了。 Vercel 对 API 请求使用缓存,因此要获取新的博客文章,您必须等到缓存失效(取决于您为其设置的时间)。
在
localhost
,数据永远不会被缓存,因此您将始终获得最新的博客文章。
如果您想在新博客文章更新时立即获取它们,您可以将重新验证持续时间设置为
0
,如下所示:
fetch("ENDPOINT", {
next: {
revalidate: 0
}
})
请参阅此文档以了解更多信息: