nextjs 提供 getServerSideProps 来获取数据,返回到props中,然后在react组件中通过props获取数据进行渲染,达到ssr效果。

    1.引入数据库和tag,article两张表

    1. import { prepareConnection } from 'db/index';
    2. import { Article, Tag } from 'db/entity';

    2.链接数据库

    1. const db = await prepareConnection();

    3.根据 关联的 user和tag查询出 所有 文章

    1. const articles = await db.getRepository(Article).find({
    2. relations: ['user', 'tags'],
    3. });

    4.根据 关联的 user 查询出 标签

    1. const tags = await db.getRepository(Tag).find({
    2. relations: ['users'],
    3. });

    5.最后将 文章和标签通过props返回

    1. return {
    2. props: {
    3. articles: JSON.parse(JSON.stringify(articles)) || [],
    4. tags: JSON.parse(JSON.stringify(tags)) || [],
    5. },
    6. };

    6.在react组件中 通过props获取 文章和标签

    1. const { articles = [], tags = [] } = props;

    7.默认将 获取的 文章,存放到所有文章的state中

    1. const [showAricles, setShowAricles] = useState([...articles]);

    8.然后渲染当前所有的文章

    1. <div className="content-layout">
    2. {showAricles?.map((article) => (
    3. <>
    4. <DynamicComponent article={article} />
    5. <Divider />
    6. </>
    7. ))}
    8. </div>

    9.上面的文章列表通过 异步加载的方式加载

    1. const DynamicComponent = dynamic(() => import('components/ListItem'));

    10.接下来 我们一起编写ListItem组件
    新建 components/ListItem/index.tsx components/ListItem/index.module.scss

    通过 props 可以获取到 从 父组件传过来的 article和 user信息

    拿到这两个信息后,将这两个字段里面的内容 渲染处理即可
    需要注意的是,需要点击谋篇文章的时候,跳转到该文章的详情页面,所以需要使用 Link

    另外一个需要注意的地方是,渲染文章的时候,文章是markdown格式
    所以使用 markdown-to-txt 第三方包 来加载 markdown格式的数据

    所以代码是这样的

    1. import Link from 'next/link';
    2. import { formatDistanceToNow } from 'date-fns';
    3. import { IArticle } from 'pages/api/index';
    4. import { Avatar } from 'antd';
    5. import { EyeOutlined } from '@ant-design/icons';
    6. import { markdownToTxt } from 'markdown-to-txt';
    7. import styles from './index.module.scss';
    8. interface IProps {
    9. article: IArticle;
    10. }
    11. const ListItem = (props: IProps) => {
    12. const { article } = props;
    13. const { user } = article;
    14. return (
    15. // eslint-disable-next-line @next/next/link-passhref
    16. <Link href={`/article/${article.id}`}>
    17. <div className={styles.container}>
    18. <div className={styles.article}>
    19. <div className={styles.userInfo}>
    20. <span className={styles.name}>{user?.nickname}</span>
    21. <span className={styles.date}>
    22. {formatDistanceToNow(new Date(article?.update_time))}
    23. </span>
    24. </div>
    25. <h4 className={styles.title}>{article?.title}</h4>
    26. <p className={styles.content}>{markdownToTxt(article?.content)}</p>
    27. <div className={styles.statistics}>
    28. <EyeOutlined />
    29. <span className={styles.item}>{article?.views}</span>
    30. </div>
    31. </div>
    32. <Avatar src={user?.avatar} size={48} />
    33. </div>
    34. </Link>
    35. );
    36. };
    37. export default ListItem;
    1. .container {
    2. margin: 0 atuo;
    3. background-color: #fff;
    4. display: flex;
    5. align-items: center;
    6. justify-content: space-between;
    7. padding: 10px;
    8. cursor: pointer;
    9. .article {
    10. width: 90%;
    11. .userInfo {
    12. margin-bottom: 10px;
    13. display: flex;
    14. align-items: center;
    15. span {
    16. padding: 0 10px;
    17. border-right: 1px solid #e5e6eb;
    18. }
    19. span:first-of-type {
    20. padding-left: 0;
    21. }
    22. span:last-of-type {
    23. border-right: 0;
    24. }
    25. .name {
    26. color: #4e5969;
    27. }
    28. .name:hover {
    29. text-decoration: underline;
    30. color: #1e80ff;
    31. }
    32. .date {
    33. color: #86909c;
    34. }
    35. }
    36. .title {
    37. font-size: 20px;
    38. overflow: hidden;
    39. text-overflow: ellipsis;
    40. white-space: nowrap;
    41. }
    42. .content {
    43. font-size: 16px;
    44. color: #86909c;
    45. overflow: hidden;
    46. text-overflow: ellipsis;
    47. white-space: nowrap;
    48. }
    49. .statistics {
    50. display: flex;
    51. align-items: center;
    52. .item {
    53. margin-left: 5px;
    54. }
    55. }
    56. }
    57. }

    看下效果:
    image.png