nextjs 提供 getServerSideProps 来获取数据,返回到props中,然后在react组件中通过props获取数据进行渲染,达到ssr效果。
1.引入数据库和tag,article两张表
import { prepareConnection } from 'db/index';import { Article, Tag } from 'db/entity';
2.链接数据库
const db = await prepareConnection();
3.根据 关联的 user和tag查询出 所有 文章
const articles = await db.getRepository(Article).find({relations: ['user', 'tags'],});
4.根据 关联的 user 查询出 标签
const tags = await db.getRepository(Tag).find({relations: ['users'],});
5.最后将 文章和标签通过props返回
return {props: {articles: JSON.parse(JSON.stringify(articles)) || [],tags: JSON.parse(JSON.stringify(tags)) || [],},};
6.在react组件中 通过props获取 文章和标签
const { articles = [], tags = [] } = props;
7.默认将 获取的 文章,存放到所有文章的state中
const [showAricles, setShowAricles] = useState([...articles]);
8.然后渲染当前所有的文章
<div className="content-layout">{showAricles?.map((article) => (<><DynamicComponent article={article} /><Divider /></>))}</div>
9.上面的文章列表通过 异步加载的方式加载
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格式的数据
所以代码是这样的
import Link from 'next/link';import { formatDistanceToNow } from 'date-fns';import { IArticle } from 'pages/api/index';import { Avatar } from 'antd';import { EyeOutlined } from '@ant-design/icons';import { markdownToTxt } from 'markdown-to-txt';import styles from './index.module.scss';interface IProps {article: IArticle;}const ListItem = (props: IProps) => {const { article } = props;const { user } = article;return (// eslint-disable-next-line @next/next/link-passhref<Link href={`/article/${article.id}`}><div className={styles.container}><div className={styles.article}><div className={styles.userInfo}><span className={styles.name}>{user?.nickname}</span><span className={styles.date}>{formatDistanceToNow(new Date(article?.update_time))}</span></div><h4 className={styles.title}>{article?.title}</h4><p className={styles.content}>{markdownToTxt(article?.content)}</p><div className={styles.statistics}><EyeOutlined /><span className={styles.item}>{article?.views}</span></div></div><Avatar src={user?.avatar} size={48} /></div></Link>);};export default ListItem;
.container {margin: 0 atuo;background-color: #fff;display: flex;align-items: center;justify-content: space-between;padding: 10px;cursor: pointer;.article {width: 90%;.userInfo {margin-bottom: 10px;display: flex;align-items: center;span {padding: 0 10px;border-right: 1px solid #e5e6eb;}span:first-of-type {padding-left: 0;}span:last-of-type {border-right: 0;}.name {color: #4e5969;}.name:hover {text-decoration: underline;color: #1e80ff;}.date {color: #86909c;}}.title {font-size: 20px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}.content {font-size: 16px;color: #86909c;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}.statistics {display: flex;align-items: center;.item {margin-left: 5px;}}}}
看下效果:
