2024. 9. 29. 13:50ㆍProgramming/ReactJS
전편에서 게시판 형태의 화면을 만들어 보았다.
이번 편에서는 글쓰기 기능을 추가해 새로운 글을 등록할 수 있게 해볼 것이다.
일단 해야 할 작업을 간단하게 나열해 보면 다음과 같다.
1) 글쓰기 버튼 추가해 누르면 글쓰기 화면으로 이동하게끔 한다.
2) 글쓰기 페이지를 만들고 제출 버튼을 누르면 글쓰기 API를 호출할 수 있게 한다.
3) nextjs 기능 중 하나인 API 기능을 활용해 입력값을 받아 새로운 글을 추가할 수 있는 API를 만든다.
4) 글쓰기가 성공적으로 완료되면 게시판 화면으로 리다이렉트한다.
1) 글쓰기 버튼 추가해 누르면 글쓰기 화면으로 이동하게끔 한다.
일단 addButton이라는 컴포넌트를 만들었다.
한 가지 유의할 점은 코드 상단에 보면 "use client"라는 게 있는데,
서버에서 렌더링되는 서버 컴포넌트가 기본인 nextjs에서 클라이언트 컴포넌트임을 명시하기 위한 것이다.
nextjs는 서버 컴포넌트, 클라이언트 컴포넌트를 엄격하게 구분하고 있으며, 클릭 같은 이벤트를 지정할 수 있는 것은 클라이언트 컴포넌트 뿐이다. 서버 컴포넌트에서 이벤트 핸들러를 지정하려고 하면 "Event handlers cannot be passed to Client Component props"라는 에러가 뜰 것이다.
이것은 useEffect 같은 react hooks, useRouter에 대해서도 마찬가지로 적용된다
"use client";
import buttonStyles from './../button.module.scss'
import { useRouter } from 'next/navigation';
export default function AddButton() {
const router = useRouter();
return <div className={buttonStyles.button}>
<button onClick={() => { router.push('/dashboard/write') }}>글쓰기</button>
</div>;
}
아래는 서버, 클라이언트 컴포넌트를 사용하는 경우의 예시니 참고하면 좋다.
구체적으로 적용해보면 이런 식으로 나누어 지정한다.
2) 글쓰기 페이지를 만들고 제출 버튼을 누르면 글쓰기 API를 호출할 수 있게 한다.
코드로 보면 다음과 같다. 입력폼, 버튼과 상호 작용이 필요하기 때문에 클라이언트 컴포넌트로 구성했다.
또한 nextjs에서 제공되는 api 호출 기능 (fetch)를 사용하여 통신 성공 후 /dashboard로 리다이렉트되도록 했다.
여기선 미리 API를 만들기 전에 호출 부분을 만들어 두었다.
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import pageStyles from './write.module.scss';
export default function Write() {
const [title, setTitle] = useState('');
const [content, setContent] = useState('');
const [author, setAuthor] = useState('');
const router = useRouter();
const handleSubmit = async (e: { preventDefault: () => void; }) => {
e.preventDefault();
const response = await fetch('/api/write', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ title, content, author }),
});
if (response.ok) {
// 폼 제출 후 입력 값 초기화
setTitle('');
setContent('');
setAuthor('');
router.push('/dashboard');
}
};
return (
<div className={pageStyles.container}>
<h1 style={{ textAlign:"center"}}>새로 글쓰기</h1>
<form className={pageStyles.form} onSubmit={handleSubmit} >
{/* 제목 입력 */}
<div className={pageStyles.field}>
<label htmlFor="title">제목:</label>
<input
type="text"
id="title"
value={title}
className={pageStyles.input}
onChange={(e) => setTitle(e.target.value)}
required
/>
</div>
{/* 글쓴이 입력 */}
<div className={pageStyles.field}>
<label htmlFor="author">글쓴이:</label>
<input
type="text"
id="author"
value={author}
className={pageStyles.input}
onChange={(e) => setAuthor(e.target.value)}
required
/>
</div>
{/* 내용 입력 */}
<div className={pageStyles.field}>
<label htmlFor="content">내용:</label>
<textarea
id="content"
value={content}
className={pageStyles.textarea}
onChange={(e) => setContent(e.target.value)}
required
/>
</div>
{/* 제출 버튼 */}
<button type="submit" className={pageStyles.button}>글쓰기</button>
</form>
</div>
);
}
이제 nextjs로 API를 만들어 보도록 하자.
src/app 폴더 아래에 api 폴더를 만들고 경로에 해당하는 폴더를 만들자.
/api/hello라는 경로로 GET 호출하는 API를 만든다고 가정해 보면,
src/app/api/hello라는 폴더를 만들고 그 안에 route.js라는 파일을 만들면 된다.
nextjs의 경우 HTTP 메소드 별로 함수를 하나씩 만드는 식인데 GET만 최대한 간단하게 만들어 보면 이렇다.
놀랍게도 단 세 줄의 코드만으로 API를 만들 수 있다 (실제 API 같은 경우는 성공, 실패시 분기 처리가 필요해 더 복잡해지긴 한다)
import { NextResponse } from 'next/server';
export async function GET(request) {
return NextResponse.json({ message: 'Hello' });
}
위 참고용 코드를 기반으로 /api/write에 POST 메소드로 접근 가능한 API를 만들어 보면 다음과 같다.
src/app/api/write/route.js
import { NextResponse } from 'next/server';
import { sql } from '@vercel/postgres';
export async function POST(request) {
try {
// 요청값에서 JSON 데이터 파싱
const { title, content, author } = await request.json();
// 유효성 검사
if (!title || !content || !author) {
return NextResponse.json(
{ error: 'title and content and author are required' },
{ status: 400 }
);
}
// SQL 쿼리를 통해 데이터 삽입
const result = await sql`
INSERT INTO board (content, name, title, views)
VALUES (${content}, ${author}, ${title}, 0);
`;
// 삽입된 데이터 반환
return NextResponse.json({ message: 'User added successfully', user: result.rows[0] }, { status: 201 });
} catch (error) {
console.error('Database error:', error);
return NextResponse.json({ error: 'Failed to add user' }, { status: 500 });
}
}
여기까지 만들고 나서 버튼을 눌러 동작시켜 보면 에러가 났다.
cmd 콘솔에서 확인해 보니 DB 관련 에러였고, 필수값인 id가 지정되어 있지 않은 것이 원인이었다.
자동으로 id값이 1, 2, 3 순서대로 들어가는 걸 원했는데 관련 설정을 하지 않은 것이다.
postgres에서 어떻게 설정하는지 모르는 상태였으므로 검색해,
다음과 같이 자동으로 값이 설정되도록 변경했다.
ALTER TABLE board
ALTER COLUMN id SET DATA TYPE INTEGER,
ALTER COLUMN id ADD GENERATED ALWAYS AS IDENTITY;
또한 작성 시간도 빈값으로 나왔기 때문에 이 부분도 레코드 생성 시간에 맞춰,
자동으로 들어갈 수 있도록 Default 값에 CURRENT_TIMESTAMP를 설정했다.
그 외에도 작성자명이 user로 되어 있는데 이게 예약어(DB에서 기본적으로 정의돼 있어 컬럼값으로 못 쓰는 단어라고 보면 된다)다 보니 문제가 생겨, 일단 name으로 바꾸어 두었다.
테이블 컬럼 설정이 모두 완료되고 나니 정상적으로 동작됐다.
dashboard로 돌아오면 다음과 같이 표시가 되는 것을 볼 수 있다.
다 만들고 나니 한 가지 문제가 발생했다.
그것은 바로 게시판 화면으로 리다이렉트됐을 때 글 갱신이 되지 않는 점이었다.
강제 새로고침을 해야만 아까 등록한 새 글이 표시가 되었다.
다음 편에서 CRUD 처리까지 모두 하고 차차 고쳐 나갈 예정이다.
C: 글쓰기 (완료)
R: 글 읽기
U: 글 수정
D: 글 삭제
이 중 다음 편에서 RUD 부분까지 완료해 보도록 하겠다.
'Programming > ReactJS' 카테고리의 다른 글
[튜토리얼] Next.js 프로젝트 시작하기 5편 - 1 (코드 포맷 툴 적용) (0) | 2024.10.13 |
---|---|
[튜토리얼] Next.js 프로젝트 시작하기 5편 (게시글 열람, 수정, 삭제 기능 추가) (3) | 2024.09.30 |
[튜토리얼] Next.js 프로젝트 시작하기 3편 (Vercel을 통해 DB를 연결하고 간단한 게시판 표시 구현) (0) | 2024.09.28 |
[튜토리얼] Next.js 프로젝트 시작하기 2편 (CSS 스타일링에서 Vercel을 통한 배포까지) (2) | 2024.09.12 |
[튜토리얼] Next.js 프로젝트 시작하기 1편 (초기 세팅에서 페이지 작성까지) (2) | 2024.09.11 |