Closed2
Next 14 App Router 使ってみた。
概要
Next 14 App Router 使う例になります。
- App Routerを選択する例です。
- 更新系は、 api route 通信する形です。
- テストは、vercelに設置する例です。
[ 公開: 2024/04/22]
環境
- Next 14
- vercel
- Turso
関連
作成したコード
ClientComponent
- app/test2/page.tsx
- ClientComponent, ServerComponent 1画面に実装できそうです。
page.tsx
import ClientCompo1 from "./ClientCompo1";
import ServerCompo1 from "./ServerCompo1";
//
export default async function Page() {
return (
<div>
<h1>Test2 !!!</h1>
<hr />
<ServerCompo1 />
<hr />
<ClientCompo1 />
</div>
);
}
- app/test2/ClientCompo1.tsx: リストの部分
- 先頭に、use client 書くとclient実装できそうです。
- 内部api (/app/api/xxxx/route.ts) と連携する例です。
- この例は、D1 + CF-workesと連携します。
ClientCompo1.tsx
"use client";
import {useState, useEffect} from 'react';
import React from 'react'
import HttpCommon from '../lib/HttpCommon';
import CrudIndex from './CrudIndex';
let pageItems: any[] = [];
//
export default function Compo() {
console.log("Client Componentを実行しています");
const [updatetime, setUpdatetime] = useState<string>("");
//
useEffect(() => {
(async () => {
setUpdatetime(new Date().toString() + String(Math.random()));
getList();
})()
}, []);
/**
*
* @param
*
* @return
*/
const getList = async function(){
try {
const item = {
"userId": 0,
}
const json = await HttpCommon.serverPost(item, "/test/get_list");
console.log(json);
pageItems = json.data;
setUpdatetime(new Date().toString() + String(Math.random()));
} catch (e) {
console.error(e);
}
}
/**
*
* @param
*
* @return
*/
const addPorc = async function(){
try {
await CrudIndex.addItem();
location.reload();
} catch (e) {
console.error(e);
}
}
//
return (
<div >
<h1>ClientCompo1.tsx</h1>
<hr />
<label>Title:</label>
<input type="text" id="title" name="title"
className="border border-gray-400 rounded-md px-3 py-2 w-full focus:outline-none focus:border-blue-500"
/>
<hr className="my-1" />
<label>Content:</label>
<input type="text" id="content" name="content"
className="border border-gray-400 rounded-md px-3 py-2 w-full focus:outline-none focus:border-blue-500"
/>
<hr className="my-1" />
<button onClick={()=>addPorc()}>Add</button>
<hr className="my-1" />
{pageItems.map((item: any ,index: number) => {
return (
<div key={index}>
<h3 className="text-3xl font-bold">{item.title}</h3>
<span>ID: {item.id}, {item.createdAt}</span>
<a href={`/testshow?id=${item.id}`}>[ Show ]</a>
<hr />
</div>
)
})}
</div>
);
}
- app/api/send_post/route.ts: 内部API (中継する中間API)
route.ts
import { NextResponse } from "next/server";
//
export async function POST(req: Request) {
try{
const reqJson = await req.json();
const url = process.env.API_URI;
const path = reqJson.api_url;
console.log("path=", url + path);
const body: any = JSON.stringify(reqJson);
const res = await fetch(url + path, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: body
});
const json = await res.json()
return NextResponse.json(json);
} catch (error) {
console.error(error);
return NextResponse.json({ret: 'NG', msg: 'sendPost_msg'});
}
}
- package.json
{
"name": "nextjs14_2",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"react": "^18",
"react-dom": "^18",
"next": "14.2.2"
},
"devDependencies": {
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18"
}
}
Turso LibSQL 使うサンプル
API
- app/api/turso_get_list/route.ts
- api routeから、直接DB連携します。
route.ts
import { NextResponse } from "next/server";
import LibTurso from '../lib/LibTurso';
//
export async function POST(req: Request) {
const retObj = {ret: "NG", data: [], message: ""};
try{
const reqJson = await req.json();
const client = await LibTurso.getClient();
const sql = `SELECT * FROM todos ORDER BY id DESC LIMIT 100;`;
console.log(sql);
const resulte = await client.execute(sql);
retObj.ret = "OK";
//@ts-ignore
retObj.data = resulte.rows;
return NextResponse.json(retObj);
} catch (error) {
console.error(error);
return NextResponse.json(retObj);
}
}
-
ClientComponent
-
app/api/turso_test/ClientCompo1.tsx
ClientCompo1.tsx
"use client";
import {useState, useEffect} from 'react';
import React from 'react'
import Link from 'next/link'
import HttpCommon from '../lib/HttpCommon';
import CrudIndex from './CrudIndex';
let pageItems: any[] = [];
//
export default function Compo() {
console.log("Client Componentを実行しています");
const [updatetime, setUpdatetime] = useState<string>("");
//
useEffect(() => {
(async () => {
setUpdatetime(new Date().toString() + String(Math.random()));
getList();
})()
}, []);
/**
*
* @param
*
* @return
*/
const getList = async function(){
try {
const json = await CrudIndex.getList()
console.log(json);
pageItems = json.data;
setUpdatetime(new Date().toString() + String(Math.random()));
} catch (e) {
console.error(e);
}
}
/**
*
* @param
*
* @return
*/
const addPorc = async function(){
try {
await CrudIndex.addItem();
location.reload();
} catch (e) {
console.error(e);
}
}
//
return (
<div >
<h1>ClientCompo1.tsx</h1>
<hr />
<label>Title:</label>
<input type="text" id="title" name="title"
className="border border-gray-400 rounded-md px-3 py-2 w-full focus:outline-none focus:border-blue-500"
/>
<hr className="my-1" />
<label>Content:</label>
<input type="text" id="content" name="content"
className="border border-gray-400 rounded-md px-3 py-2 w-full focus:outline-none focus:border-blue-500"
/>
{/*
<button onClick={()=>addPorc()}>Add</button>
<hr className="my-1" />
*/}
<hr className="my-1" />
{pageItems.map((item: any ,index: number) => {
return (
<div key={index}>
<h3 className="text-3xl font-bold">{item.title}</h3>
<span>ID: {item.id}, {item.createdAt}</span>
<hr />
</div>
)
})}
</div>
);
}
- package.json
{
"name": "nextjs14_2",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@libsql/client": "^0.6.0",
"next": "14.2.2",
"react": "^18",
"react-dom": "^18"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"typescript": "^5"
}
}
このスクラップは2024/04/26にクローズされました