目的
通过此案例,可以简单快速的过一下数据库的操作,熟悉app-router这种模式下,client component和server component的两种组件中基本的接口使用。
技术栈
- nextjs@14.2.* app-router
- @vercel/postgres@0.10.*
- typescript@5
重要事情说三遍1
- app-router!!! 下面所有的代码和目录结构,脱离不开这个模式
- app-router!!! 下面所有的代码和目录结构,脱离不开这个模式
- app-router!!! 下面所有的代码和目录结构,脱离不开这个模式
创建表
初始化操作,可以看 最新nextjs中使用postgresSQL 这里
sql语句:CREATE TABLE article (content TEXT);
创建一个存放文章内容的表,字段为
content
并且类型为TEXT
. 详细的数据类型可以看这里
字符类型 | 描述 |
---|---|
character varying(n), varchar(n) | 变长,有长度限制 |
character(n), char(n) | 定长,不足补空白 |
text | 变长,无长度限制 |
创建文章数据(服务端)
sql语句:INSERT INTO article VALUES (${body.content});
接口文件:src/api/add-acticle/route.ts
import { sql } from '@vercel/postgres';
import { NextResponse } from 'next/server';
export async function GET() {
const { rows } = await sql`SELECT * FROM article`;
return Response.json({ rows })
}
export async function POST(request: Request) {
const body = await request.json();
await sql`INSERT INTO article VALUES (${body.likes});`;
return NextResponse.json({ status: 200 });
}
创建文章数据(客户端)
目录:src/app/components/create-comp/index.tsx
涉及到react hook使用的组件,必须是use client
- 以下出现的
gyp-gao-ui
组件库已发布到npm,如果只是想demo下,自行npm i -S gyp-gao-ui
即可,使用中出现问题,可以看 nextjs中集成富文本编辑器wangEditor - 或者就是换成随便一个输入框
getHostStatic
方法的代码
"use client";
import { RichText } from "gyp-gao-ui";
import { useState } from "react";
import { getHostStatic } from '../../../utils/static-index';
export default function CreateText() {
const [data, setData] = useState('');
const handleInsert = async () => {
const res = await fetch(
`${getHostStatic()}/api/add-acticle`,
{
method: "post",
body: JSON.stringify({
content: data,
}),
}
);
// 这里res可以自己在服务端那边组装成想要的格式哦
// 然后前端这边就自行根据不同的结果做一些正常/异常处理
};
const handleChange = (value: string) => {
setData(value);
}
return (
<div>
<RichText onChange={handleChange} />
<div className="btn" onClick={handleInsert}>保存数据</div>
</div>
);
}
目录:src/app/create/page.tsx
主创建页面,服务端渲染的
import dynamic from 'next/dynamic'
import { Metadata } from 'next';
import './a.scss'; // 天然支持的scss/sass
const RichText = dynamic(() => import("../components/create-comp"), {
ssr: false,
});
export const metadata: Metadata = {
title: '创建数据',
}
export default async function CreateText() {
return (
<div className='a'>
<RichText />
</div>
);
}
查询展示文章数据 (客户端)
服务端数据生成和渲染
getHost
方法代码如下,切记该代码的运行环境不能是use client
目录:src/utils/index.ts
服务端怎么知道当前项目的域名,通过headers上面的字段查询,官方文档
import { headers } from 'next/headers';
const logPrefix = '[blog-render]:--> '
/** 获取当前域名 */
export const getHost = () => {
const headersList = headers();
// https://developer.mozilla.org/docs/Web/API/Headers/get
// https://nextjs.org/docs/app/api-reference/functions/headers
const host = headersList.get('host');
const xForwardedHost = headersList.get('x-forwarded-host');
const referer = headersList.get('referer');
const protocol = headersList.get('x-forwarded-proto');
console.info(logPrefix + 'url:===', host, referer, protocol)
// 获取协议
const realProtocol = referer?.split('://')[0] || protocol;
const realHost = host || xForwardedHost;
console.info(logPrefix + 'realUrl:==', realProtocol, realHost)
const url = `${realProtocol}://${realHost}`;
return url;
}
目录:src/app/components/pre-comp/index.tsx
"use client";
import { RichTextRender } from "gyp-gao-ui";
export default function Preview({ content }: {content: string}) {
return (
<div style={{marginBottom: '30px'}}>
<RichTextRender content={content} />
</div>
);
}
目录:src/app/preview/pages.tsx
import { Metadata } from 'next';
import dynamic from 'next/dynamic';
import { getHost } from '../../utils';
export const metadata: Metadata = {
title: '欢迎预览',
}
const RichTextReader = dynamic(() => import("../components/pre-comp"), {
ssr: false,
});
export default async function Preview() {
const url = getHost();
const data = await fetch(`${url}/api`);
const { rows } = await data.json();
return (
<div>
{rows.map((o: { content: string }, i: number) => <RichTextReader key={i} content={o.content} />)}
</div>
)
}
效果如下
列表数据展示如下,当然demo就不写那么美观的css了!
写在最后
找到正确的打开入口,学习就会事半功倍,觉醒吧前端同志。记得给博主点个赞,制作不易,感谢大家捧场!!!
还是希望大家,可以多多评论区讨论 ↩︎