单页静态生成和SWR

Static generation and SWR in single page

我正在 Next.js 中构建博客网站,博客的 API 来自一些无头 CMS。

我想在页面中执行以下操作:

  1. 列出一些博客。
  2. 一组可用的按钮,根据每个按钮的点击不同的一组博客正在加载(应该替换#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>
    )
}