NextJS 13 버전
포켓베이스를 이용하여 간단한 게시판 리스트와 뷰페이지, 글쓰기 기능을 갖춘 웹페이지를 만들것이다.
Nextjs 13버전 설치npx create-next-app --next=13.1.1 ./ --ts
// 이렇게 설치했는데 14버전이 설치됨...
포켓베이스 설치와 설정(백엔드)
다운로드해서 압축풀고
pocketbase.exe 파일을 프로젝트안의 최상위 경로에 넣는다.
실행방법은 간단하다.. ../pocketbase serve
Admin UI주소로 들어가보면
계정생성하여 로그인한다.
posts라는 이름의 데이터테이블을 만드는데 여기서는 collection이다.
new field로 컬럼추가 가능
그리고 세팅 > API Rules > Unlock and set custom rule을 클릭하여 set admins only로 바꿔준다
라우팅
pages안에서 파일시스템을 라우팅했지만
이제 app폴더 안에서 파일시스템 라우팅을 할것이다... (베타버전)
home/
👉 abc.com/home plain path[slug]/
👉 abc.com/{slug} dynamic path(group)/
👉 abc.com/ just for grouping
해당 라우터 url을 폴더로 만들고
그안에 index.tsx를 만드는게 아닌 page.tsx
만들어 페이지를 생성해야 파일시스템 라우팅이 된다.
Server Component
React 18이전에는 React를 사용하여 애플리케이션을 렌더링하는 기본 방법은 전적으로 클라이언트에서였다. 18이후부터 서버컴포넌트 사용이 가능하다.
Next.js는 HTML을 생성하고 React에 의해 rehydrate되도록 클라이언트에 전송함으로써 애플리케이션을 페이지로 나누고 서버에서 미리 렌더링하는 더 쉬운 방법을 제공했다. 그러나 이로 인해 초기 HTML을 대화식으로 만들기 위해 클라이언트에 추가 Javascript가 필요했다.
=> 서버에서 미리 렌더링 하기위해 사용했던 SSR도 문제가 있었다.
이제 서버 및 클라이언트 Component를 사용하여 React는 클라이언트와 서버에서 렌더링 할 수 있으므로 구성요소 수준에서 렌더링 환경을 선택할 수 있다. 기본적으로 App디렉터리는 서버 컴포넌트를 사용하므로 서버에서 컴포넌트를 쉽게 렌더링하고 클라이언트에 전송되는 Javascript 양을 줄일 수 있다. 그러나 App내엥서 클라이언트 구성요소를 사용하고 클라이언트에서 렌더링 할 수 있는 옵션이 있다.
=> Server Component, Client Component 같이 사용 가능
Posts List 페이지
/app/posts/page.tsx
import Link from 'next/link';
// get data
async function getPosts() {
const res = await fetch('http://127.0.0.1:8090/api/collections/posts/records');
const data = await res.json();
return data?.items as any[];
}
const PostsPage = async () => {
const posts = await getPosts();
return (
<div>
<h1>Posts</h1>
{posts?.map((post) => {
return <PostItem key={post.id} post={post} />
})}
</div>
)
}
const PostItem = ({ post }: any) => {
const { id, title, created } = post || {};
return (
<Link href={`/posts/${id}`}>
<h2>{title}</h2>
<p>{created}</p>
</Link>
);
};
export default PostsPage;
Dynamic Data Fetching
현재 getPost로 한번 가져오면 캐시가 다 되어버림.
경로 자체가 다이나믹하지 않고 딱 하나의 경로만 되어있음.
=> 캐싱을 사용하지 않고 매번 요청을 보낼때마다 가져오게 하려면?
Dynamic Data Fetching{ cache: 'no-store' }
-> 캐시가 안되게 하고 모든 리퀘스트마다 다시 가져올 수 있게 한다.
async function getPosts() {
const res = await fetch(
'http://127.0.0.1:8090/api/collections/posts/records',
{ cache: 'no-store' }
);
const data = await res.json();
return data?.items as any[];
}
getServerSideProps과 유사함
Post Detail 페이지
Revalidating data
캐시된 데이터를 일정 시간간격으로 재검증.fetch()
에서 next.revalidate
옵션을 사용할 수 있다.
기본단위는 초
이다.
async function getPost(postId: string) {
const res = await fetch(
`http://127.0.0.1:8090/api/collections/posts/records/${postId}`,
{ next: {revalidate: 10 } } // revalidating data: 캐시된 데이터를 일정 시간간격으로 재검증
);
const data = await res.json();
return data?.items as any[];
}
generateStaticParams
generateStaticParams함수는 해당 레이아웃 또는 페이지가 생성되기 전에 빌드시간에 실행된다. Revalidation(ISR)중에는 다시 호출되지 않는다.
getStaticPaths와 유사
포스트 페이지, 포스트 데이터 받아오기
import React from 'react'
async function getPost(postId: string) {
const res = await fetch(
`http://127.0.0.1:8090/api/collections/posts/records/${postId}`,
{ next: {revalidate: 10 } } // revalidating data: 캐시된 데이터를 일정 시간간격으로 재검증
);
const data = res.json();
return data;
}
const PostDetailPage = async ({params}: any) => {
const post = await getPost(params.id);
return (
<div>
<h1>posts/{post.id}</h1>
<h2>{post.title}</h2>
<div>{post.created}</div>
</div>
)
}
export default PostDetailPage
error handling
https://nextjs.org/docs/app/building-your-application/routing/error-handling
response가 ok되지 않으면 에러 throw를 하는 코드를 추가한다.
그러면 가장 가까이에 있는 error.js 파일이 활성화된다.
같은경로에 error.tsx
를 만들고 (샘플코드는 공식문서에 있음)
fetch하는 url에 일부러 오타를 내보자.
/app/posts/[id]/page.tsx
async function getPost(postId: string) {
const res = await fetch(
`http://127.0.0.1:8090adf/api/collections/posts/records/${postId}`,
{ next: {revalidate: 10 } } // revalidating data: 캐시된 데이터를 일정 시간간격으로 재검증
);
if(!res.ok) {
// 가장 가까이에 있는 error.js activated
throw new Error('Failed to fetch data');
}
const data = res.json();
return data;
}
이렇게 에러처리가 되고 준비해둔 UI가 보인다.
Create Post
클라이언트 컴포넌트로 생성한다. 상단에 'use client'
를 추가.
'use client'
import { useState } from "react";
const CreatePost = () => {
const [title, setTitle] = useState('');
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
await fetch('http://127.0.0.1:8090/api/collections/posts/records', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
title
})
});
setTitle('')
}
return (
<form onSubmit={handleSubmit}>
<input type="text"
placeholder="title"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<button type="submit">Create Post</button>
</form>
)
}
export default CreatePost
포스트 리스트 페이지에 컴포넌트를 추가하면 인풋에 내용(타이틀)을 입력하고 제출하고 새로고침을 하면 리스트에 추가된것을 확인 할 수 있다.
하지만 새로고침 없이 리스트에 자동으로 추가되었으면한다.
refresh()
refresh()를 호출하면 현재 경로가 서버에서 업데이트된 할일 목록을 새로 고침하고 가져온다. 이는 브라우저기록에 영향을 미치지 않지만 루트 레이아웃에서 아래로 데이터를 새로 고친다. refresh()를 사용할때 React 및 브라우저 상태를 모두 포함하여 클라이언트 측 상태(state)가 손실되지 않는다.
=> full page refresh 를 안해도 된다.
import { useRouter } from "next/navigation";
import { useState } from "react";
const CreatePost = () => {
const [title, setTitle] = useState("");
const router = useRouter(); // "next/navigation"
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
await fetch("http://127.0.0.1:8090/api/collections/posts/records", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
title,
}),
});
setTitle("");
router.refresh();
};
return (
...
useRouter()
를 next/navigation
에서 import해와서 data fetch후 router.refresh()
한다.
'Frontend > Next.js' 카테고리의 다른 글
Nextjs 프로젝트 git pull/clone 받고 실행 오류 (0) | 2024.02.02 |
---|---|
[Next.js] 중고마켓 앱2 (1) | 2024.02.01 |
[Next.js] 중고마켓 앱1 (0) | 2024.02.01 |
[Next.js] 튜토리얼 블로그 (0) | 2024.01.17 |
[Next.js] Next.js 기본 (0) | 2024.01.17 |