생성 기능을 구현하기 위해서는 onSubmit과 같은 사용자와 상호작용하는 코드가 필요합니다. 이런 코드는 서버 쪽에서 실행할 수 없기 때문에 클라이언트 쪽으로 전송되어서 실행되야 합니다. 여기서는 클라이언트 컴포넌트를 만드는 방법을 살펴봅니다.

소스코드
https://github.com/egoing/nextapp/commit/0a316f1e31a52729607bc190d5c5e65483a71e20
절차
1. app/create/layout.js 삭제
이 파일은 중첩된 layout을 보여주기 위해서 만든 임시 파일이기 때문에 삭제 합니다.
2. app/create/page.js 수정
'use client'
import { useRouter } from "next/navigation";
export default function Create(){
const router = useRouter();
return <form onSubmit={async evt=>{
evt.preventDefault();
const title = evt.target.title.value;
const body = evt.target.body.value;
const resp = await fetch('http://localhost:9999/topics/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({title, body})
});
const topic = await resp.json();
console.log("file: page.js:19 ~ Create ~ topic:", topic)
router.push(`/read/${topic.id}`);
router.refresh();
}}>
<h2>Create</h2>
<p><input type="text" name="title" placeholder="title" /></p>
<p><textarea name="body" placeholder="body"></textarea></p>
<p><input type="submit" value="create" /></p>
</form>
}
3. server component -> client component
'use client'
위의 코드를 사용하면 client component로 전환됩니다. 클라이언트 컴포넌트가 되면 useEffect, useState, onSubmit과 같은 코드를 사용할 수 있게 됩니다.
4. 라우터
const router = useRouter();
useRouter를 사용하면 라우터 객체를 생성할 수 있습니다. useRouter는 client component에서만 사용 가능합니다.
5. 라우터 사용
router.push(`/read/${topic.id}`);
router.refresh();
router.push를 사용하면 페이지 리로드 없이 사용자의 화면을 해당 페이지로 이동합니다. router.refresh를 사용하면 서버 컴포넌트를 서버 쪽에서 다시 랜더링해서 새로 고침할 수 있습니다. 여기서는 app/layout.js을 새로고침하기 위해서 사용된 코드입니다.
6. cache 업데이트
router.refresh를 했음에도 글 목록이 갱신되지 않을 것입니다. 그 이유는 서버쪽에서 fetch를 사용하면 응답 결과를 저장하기 때문입니다. 개발 서버를 다시 시작하고, 페이지를 리로드한 후에 터미널을 봅시다.

루트 페이지(/)로 접속했을 때 app/layout.js에서 fetch가 동작해서 http://localhost:3000/api/topics/로 접속이 발생했다는 뜻입니다. cache : MISS는 캐쉬가 없기 때문에 서버에 실제로 접속해서 데이터를 가져왔다는 뜻입니다.
다시 접속하면 아래와 같이 됩니다.

cache : HIT 입니다. 캐쉬를 사용했다는 뜻입니다.
캐쉬를 삭제한 후에 router.refresh를 하면 됩니다만, 그건 수업의 범위를 벗어나기 때문에 fetch를 하는 단계에서 캐쉬를 사용하지 않는 방법을 보여드리겠습니다. 자세한 내용은 revalidate를 확인해주세요.
7. app/layout.js 편집
import Link from 'next/link'
import './globals.css'
export const metadata = {
title: 'WEB tutorial',
description: 'Generated by egoing',
}
export default async function RootLayout({ children }) {
const resp = await fetch('http://localhost:9999/topics/', {cache:'no-cache'})
const topics = await resp.json();
console.log('page/layout.js/topics', topics)
return (
<html>
<body>
<h1><Link href="/">WEB</Link></h1>
<ol>
{topics.map(topic=>{
return <li key={topic.id}><Link href={`/read/${topic.id}`}>{topic.title}</Link></li>
})}
</ol>
{children}
<ul>
<li><Link href="/create">create</Link></li>
<li><Link href="/update/id">update</Link></li>
<li><button>delete</button></li>
</ul>
</body>
</html>
)
}
위의 코드는 아래 부분이 변경되었습니다.
const resp = await fetch('http://localhost:9999/topics/', {cache:'no-cache'})
{cache:'no-cache'}를 추가하면 캐쉬를 사용하지 않게 됩니다.
이제 layout.js의 fetch는 랜더링 될 때마다 캐쉬를 사용하지 않고 신선한 데이터를 가져오게 되었습니다.

