单页静态生成和SWR
Static generation and SWR in single page
我正在 Next.js 中构建博客网站,博客的 API 来自一些无头 CMS。
我想在页面中执行以下操作:
- 列出一些博客。
- 一组可用的按钮,根据每个按钮的点击不同的一组博客正在加载(应该替换#1 中的博客)。
由于需要 SEO,所以我很困惑应该选择哪种方法。
我认为生成初始列表的方式
getStaticProps
(静态生成),加载后我想根据用户操作(按钮单击)替换博客。
但是我很困惑,是否可以在单页中使用静态生成和SWR?
这是我的实现。
pages/index.js
export async function getStaticProps() {
const resPosts = await fetch(`${process.env.API_BASE_URL}posts?per_page=4&&_embed`)
const posts = await resPosts.json()
return {
props: {
posts
},
revalidate:10
}
}
export default function Home({posts}) {
return (
<div>
//pass data to FeaturedBlogs component (Components/featuredBlogs.js)
<FeaturedBlogs categories={categories} posts={posts} />
</div>
)
}
Components/featuredBlogs.js
const FeaturedBlogs = ({posts }) => {
return (
<div className={`${blogStyles.feature_blogs_wrap}`}>
//need to load the below blogs based on button click
<button onClick={handleClick('health')}>Health</button>
<button onClick={handleClick('latest')}>Latest</button>
//listing blogs
{posts.map((item ) => (
<Link key={item.id} href="/blog/view" passHref={true}>
<section>
<Image alt="blog_img" src={item._embedded['wp:featuredmedia'][0].media_details.sizes.medium.source_url} width="200" height="200" />
<div className={`${blogStyles.feature_blogs_content}`}>
<div className={`${blogStyles.feature_blogs_label}`}>
<span>{item._embedded['wp:term'][0][0].name}</span>
</div>
<p>{item.title.rendered}</p>
<div className={`${blogStyles.feature_blogs_author}`}>
<Image alt="author" src={item._embedded.author[0].avatar_urls[48]} width="200" height="200" />
<span>{item._embedded.author[0].name}</span>
</div>
</div>
</section>
</Link>
))}
</div>
)
}
const handleClick = (id) => {
//console.log(id)
}
我需要的是在 handleClick
事件中加载博客,但问题是这不起作用,因为它是在构建时从服务器生成的。
在 FeaturedBlogs
组件中,您可以创建一个状态变量来跟踪客户端选择新类别的时间。
const [category, setCategory] = useState()
然后您可以useSWR
根据这个category
变量的值有条件地获取数据。
const { data, loading } = useSWR(category ? [category] : null, fetcher)
fetcher
函数将具有获取给定类别的帖子的逻辑。
const fetcher = async (category) => {
const response = await fetch(/* Endpoint to get posts for given category */)
return await response.json()
}
有了这个,当 category
未设置时,您可以让组件默认呈现在 getStaticProps
中检索到的 posts
。这将发生在页面的初始呈现上。但是,当单击按钮并设置 category
时,将获取并呈现该类别的数据。
这是原始组件的修改版本的完整代码。
// Components/featuredBlogs.js
const fetcher = async (category) => {
const response = await fetch(/* Endpoint to get posts for given category */)
return await response.json()
}
const FeaturedBlogs = ({ posts }) => {
// Add state variable to keep track of the selected category
const [category, setCategory] = useState()
// Fetch posts from category only if `category` is set
const { data, loading } = useSWR(category ? [category] : null, fetcher)
const handleClick = (cat) => () => {
setCategory(cat)
}
// If `category` is set render data with post for given category, otherwise render all posts from `getStaticProps`
const itemsToRender = category ? data : posts
return (
<div className={blogStyles.feature_blogs_wrap}>
<button onClick={handleClick('health')}>Health</button>
<button onClick={handleClick('latest')}>Latest</button>
{loading && <div>Loading...</div>}
{!!itemsToRender?.length && itemsToRender.map((item) => (
<!-- Render items here -->
))}
</div>
)
}
我正在 Next.js 中构建博客网站,博客的 API 来自一些无头 CMS。
我想在页面中执行以下操作:
- 列出一些博客。
- 一组可用的按钮,根据每个按钮的点击不同的一组博客正在加载(应该替换#1 中的博客)。
由于需要 SEO,所以我很困惑应该选择哪种方法。
我认为生成初始列表的方式
getStaticProps
(静态生成),加载后我想根据用户操作(按钮单击)替换博客。
但是我很困惑,是否可以在单页中使用静态生成和SWR?
这是我的实现。
pages/index.js
export async function getStaticProps() {
const resPosts = await fetch(`${process.env.API_BASE_URL}posts?per_page=4&&_embed`)
const posts = await resPosts.json()
return {
props: {
posts
},
revalidate:10
}
}
export default function Home({posts}) {
return (
<div>
//pass data to FeaturedBlogs component (Components/featuredBlogs.js)
<FeaturedBlogs categories={categories} posts={posts} />
</div>
)
}
Components/featuredBlogs.js
const FeaturedBlogs = ({posts }) => {
return (
<div className={`${blogStyles.feature_blogs_wrap}`}>
//need to load the below blogs based on button click
<button onClick={handleClick('health')}>Health</button>
<button onClick={handleClick('latest')}>Latest</button>
//listing blogs
{posts.map((item ) => (
<Link key={item.id} href="/blog/view" passHref={true}>
<section>
<Image alt="blog_img" src={item._embedded['wp:featuredmedia'][0].media_details.sizes.medium.source_url} width="200" height="200" />
<div className={`${blogStyles.feature_blogs_content}`}>
<div className={`${blogStyles.feature_blogs_label}`}>
<span>{item._embedded['wp:term'][0][0].name}</span>
</div>
<p>{item.title.rendered}</p>
<div className={`${blogStyles.feature_blogs_author}`}>
<Image alt="author" src={item._embedded.author[0].avatar_urls[48]} width="200" height="200" />
<span>{item._embedded.author[0].name}</span>
</div>
</div>
</section>
</Link>
))}
</div>
)
}
const handleClick = (id) => {
//console.log(id)
}
我需要的是在 handleClick
事件中加载博客,但问题是这不起作用,因为它是在构建时从服务器生成的。
在 FeaturedBlogs
组件中,您可以创建一个状态变量来跟踪客户端选择新类别的时间。
const [category, setCategory] = useState()
然后您可以useSWR
根据这个category
变量的值有条件地获取数据。
const { data, loading } = useSWR(category ? [category] : null, fetcher)
fetcher
函数将具有获取给定类别的帖子的逻辑。
const fetcher = async (category) => {
const response = await fetch(/* Endpoint to get posts for given category */)
return await response.json()
}
有了这个,当 category
未设置时,您可以让组件默认呈现在 getStaticProps
中检索到的 posts
。这将发生在页面的初始呈现上。但是,当单击按钮并设置 category
时,将获取并呈现该类别的数据。
这是原始组件的修改版本的完整代码。
// Components/featuredBlogs.js
const fetcher = async (category) => {
const response = await fetch(/* Endpoint to get posts for given category */)
return await response.json()
}
const FeaturedBlogs = ({ posts }) => {
// Add state variable to keep track of the selected category
const [category, setCategory] = useState()
// Fetch posts from category only if `category` is set
const { data, loading } = useSWR(category ? [category] : null, fetcher)
const handleClick = (cat) => () => {
setCategory(cat)
}
// If `category` is set render data with post for given category, otherwise render all posts from `getStaticProps`
const itemsToRender = category ? data : posts
return (
<div className={blogStyles.feature_blogs_wrap}>
<button onClick={handleClick('health')}>Health</button>
<button onClick={handleClick('latest')}>Latest</button>
{loading && <div>Loading...</div>}
{!!itemsToRender?.length && itemsToRender.map((item) => (
<!-- Render items here -->
))}
</div>
)
}