【问题标题】:Static generation and SWR in single page单页静态生成和 SWR
【发布时间】:2022-01-25 13:09:47
【问题描述】:

我正在用 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 事件中加载博客,但问题是这不起作用,因为它是在构建时从服务器生成的。

【问题讨论】:

  • “是否可以在单页中使用静态生成和 SWR” - 是的,可以这样做。您对实施有任何具体问题吗?我建议阅读SWR Usage with Next.js。
  • 我在实现上有一些问题,请你看看@juliomalves
  • 您是否能够从 API 中获取特定类别的帖子?
  • 是的,这是可能的

标签: javascript next.js swr


【解决方案1】:

在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>
    )
}

【讨论】:

    猜你喜欢
    • 2020-07-29
    • 2019-09-02
    • 1970-01-01
    • 2012-07-08
    • 2021-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    相关资源
    最近更新 更多