Next.js 服务器组件转换为客户端组件时出现问题

Kar*_*kur 1 javascript reactjs next.js

我正在使用 next.js 开发一个博客网站。我有一个主页,它是一个服务器组件,但现在我希望它更改为客户端组件,以便我可以使其具有交互性(集成分页)。

但是,当我将代码转换为客户端组件时,它开始给我带来问题,例如浏览器窗口在打开 localhost 时似乎有时会卡住。还有api请求getPosts方法没有通过 React 的 useState 的 setState 函数进行存储。

下面给出的是主页的先前服务器组件 -

import { getCategoryPosts, getPosts } from '@/services'
import styles from '../../app/page.module.scss'
import PostCard from './PostCard'

type Props = { categorySlug?: string }

async function HomePagePosts({ categorySlug = '' }: Props) {
  const { postsContainer } = styles
  let posts
  if (!categorySlug) {
    posts = await getPosts()
  } else {
    posts = await getCategoryPosts(categorySlug)
  }

  return (
    <section className={postsContainer}>
      {posts.map((post) => (
        <PostCard post={post} key={post.title}></PostCard>
      ))}
    </section>
  )
}

export default HomePagePosts

Run Code Online (Sandbox Code Playgroud)

下面是新的客户端组件 -

'use client'

import { useEffect, useState } from 'react'
import { getCategoryPosts, getPosts } from '@/services'
import styles from '../../app/page.module.scss'
import PostCard from './PostCard'

type Props = { categorySlug?: string }

function HomePagePosts({ categorySlug = '' }: Props) {
  const [posts, setPosts] = useState([])

  useEffect(() => {
    async function setAllPosts() {
      if (!categorySlug) {
        setPosts(await getPosts())
      } else {
        setPosts(await getCategoryPosts(categorySlug))
      }
    }
    setAllPosts()
  }, [])

  const { postsContainer } = styles

  return (
    <section className={postsContainer}>
      {posts.map((post) => (
        <PostCard post={post} key={post.title}></PostCard>
      ))}
    </section>
  )
}

export default HomePagePosts

Run Code Online (Sandbox Code Playgroud)

上面的代码导致无限循环,导致窗口被卡住,并且帖子状态渲染为空并且不更新。

尽管如果我控制台记录该getPosts()方法,它会返回正确的内容,因此此转换存在问题。

编辑 -

我注意到一些事情——

return (
    <section className={postsContainer}>
      help
      {posts?.map((post) => (
        <div key={post.title}>{post.title}</div>
        // <PostCard post={post} key={post.title}></PostCard>
      ))}
    </section>
  )
Run Code Online (Sandbox Code Playgroud)

上面的代码给出了正确的 post.title 内容

但如果我使用该<PostCard/>组件,则只有它继续加载并进入无限循环,并且不会在帖子状态中显示任何内容。

PostCard 组件是一个服务器组件,它是一个异步功能组件,所以这会是问题吗?

这是明信片代码 -

import { postsType } from '@/utils/types/types'
import styles from '../../app/page.module.scss'
import moment from 'moment'
import Link from 'next/link'
import Image from 'next/image'
import { myPortfolioURL } from '@/services'
import LikeButton from '../buttons/LikeButton'
import CommentButton from '../buttons/CommentButton'

type Props = { post: postsType }

async function PostCard({ post }: Props) {
  const {
    postCard,
    postImage,
    title,
    summary,
    authorName,
    authorInfo,
    authorInfoContainer,
    authorImage,
    date,
    icon,
    userFeedbackContainer,
    leftAlign,
    rightAlign,
    readTimeContainer,
    postReactionSection,
  } = styles
  const authorId: string = (await myPortfolioURL(post.author.id)) || '/'
  return (
    <div className={postCard}>
      <div className={authorInfoContainer}>
        <Link
          href={authorId}
          className={authorInfo}
          rel="noopener noreferrer"
          target="_blank"
        >
          <div className={authorImage}>
            <Image
              src={post.author.photo.url}
              style={{ objectFit: 'cover', borderRadius: '50%' }}
              sizes="(max-width: 768px) 40px, (max-width: 1200px) 50px, 40px"
              fill={true}
              alt={post.author.name}
            />
          </div>
          <p className={authorName}>{post.author.name}</p>
        </Link>

        <div className={date}>
          <p>{moment(post.createdAt).format('MMM DD, YYYY')}</p>
        </div>
      </div>
      <Link href={`/post/${post.slug}`}>
        <div className={postImage}>
          <Image
            src={post.featuredImage.url}
            style={{ objectFit: 'cover', borderRadius: '.5rem' }}
            fill={true}
            alt={post.title}
          />
        </div>
      </Link>

      <h1>
        <Link href={`/post/${post.slug}`} className={title}>
          {post.title}
        </Link>
      </h1>
      <div className={summary}>{post.summary}</div>
      <div className={postReactionSection}>
        <div className={leftAlign}>
          <div className={userFeedbackContainer}>
            <LikeButton postId={post.id} />
            <CommentButton postId={post.id} />
          </div>
        </div>
        <div className={rightAlign}>
          <div className={readTimeContainer}>{post.readTime} min read</div>
        </div>
      </div>
    </div>
  )
}

export default PostCard

Run Code Online (Sandbox Code Playgroud)

may*_*513 5

你不能有异步效果。因此你需要执行以下操作

 useEffect(() => {
    getPosts().then(data => setPosts(data)); 
  }, [])
Run Code Online (Sandbox Code Playgroud)

更新:

根据更新的问题。我注意到您正在使用服务器组件PostCard作为client component. 这就是错误的原因。客户端组件的所有子组件始终是客户端组件。

因此,您应该从客户端组件中删除服务器端代码,并使其不是异步的。