👥Club/☁️9oormthon univ☁️
☁️ 토이 프로젝트 - React+TypeScript+Next.js 📋
비엔 Vien
2025. 5. 28. 13:55
자 저는 감자기 때문에
봐도 봐도 모르기 때문에 강의를 다시보며 합니당. ㅋ
Props : 43 44
다른 파일에서 해당 메소드 사용가능하려면
export default function Header {
~~
}
그리고 다른 파일에서 가져오려면
import Header from './components/Header.jsx'
48강의 - children
49 이벤트 처리하기 (onClick 같은거)
50, 51(매개변수 파라미터 넣어주는 경우는 종류 구별할때??)
52 tabcontent button
53 reactHook와 state ,
54 뭐 아래 내용 여러개 뜨게 하던거
<main className="min-h-screen bg-[rgb(117,181,237)] flex items-center justify-center px-4 py-8">
<form
onSubmit={handleSubmit(onSubmit)}
className="w-full max-w-2xl bg-white border-2 border-[rgb(0, 0, 0)] rounded-lg p-8 shadow-md"
>
<h1 className="text-3xl font-bold mb-6 text-center text-black">
{isEdit ? "게시글 수정" : "게시글 작성"}
</h1>
<div className="space-y-4">
<div>
<label htmlFor="title" className="text-sm font-semibold mb-1">
제목
</label>
<input
id="title"
{...register("title", { required: true })}
className="w-full p-2 border rounded bg-[rgb(239,246,255)]"
/>
{errors.title && (
<p className="text-red-500 text-sm mt-1">제목을 입력해주세요.</p>
)}
</div>
<div>
<label htmlFor="author" className="text-sm font-semibold mb-1">
닉네임
</label>
<input
id="author"
{...register("author", { required: true })}
className="w-full p-2 border rounded bg-[rgb(239,246,255)]"
/>
{errors.author && (
<p className="text-red-500 text-sm mt-1">
닉네임을 입력해주세요.
</p>
)}
</div>
<div>
<label htmlFor="password" className="text-sm font-semibold mb-1">
비밀번호
</label>
<input
type="password"
id="password"
{...register("password", { required: true })}
className="w-full p-2 border rounded bg-[rgb(239,246,255)]"
/>
{errors.password && (
<p className="text-red-500 text-sm mt-1">
비밀번호를 입력해주세요.
</p>
)}
</div>
<div>
<label htmlFor="content" className="text-sm font-semibold mb-1">
내용
</label>
<textarea
id="content"
rows={10}
{...register("content", { required: true })}
className="w-full p-2 border rounded bg-[rgb(239,246,255)]"
/>
{errors.content && (
<p className="text-red-500 text-sm mt-1">내용을 입력해주세요.</p>
)}
</div>
<div className="flex justify-end space-x-2">
<Link
href="/"
className="px-4 py-2 border rounded hover:bg-gray-100"
>
취소
</Link>
<button
type="submit"
className="bg-[rgb(80,147,234)] text-white px-4 py-2 rounded hover:bg-[rgb(44,120,221)]"
>
{isEdit ? "수정하기" : "작성하기"}
</button>
</div>
</div>
</form>
</main>
흠.. 강의를 봅세요
"use client";
import { useState, useEffect } from "react";
import { useSearchParams } from "next/navigation";
import Link from "next/link";
export default function Write() {
const searchParams = useSearchParams();
const postId = searchParams.get("id");
const isEdit = !!postId;
//입력값마다 개별 useState()로 별도의 상태 관리
const [enteredTitle, setEnteredTitle] = useState("");
const [enteredAuthor, setEnteredAuthor] = useState("");
const [enteredPassword, setEnteredPassword] = useState("");
const [enteredContent, setEnteredContent] = useState("");
useEffect(() => {
if (isEdit) {
// 기존 게시글 데이터 (임시)
setEnteredTitle("기존 게시글 제목");
setEnteredAuthor("기존 작성자");
setEnteredPassword("");
setEnteredContent("기존 게시글 내용");
}
}, [isEdit]);
const handleSubmit = (event: React.FormEvent) => {
event.preventDefault();
// 게시글 작성/수정 로직 구현
};
return (
);
}
폼 항목 여러개니까 일괄처리하려고 form이라는 하나의 객체로 모든 필드 관리
useRouter로 홈으로 이동
'use client';
import { useState, useEffect } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import Link from 'next/link';
interface PostForm {
title: string;
author: string;
password: string;
content: string;
}
export default function Write() {
const router = useRouter();
const searchParams = useSearchParams();
const postId = searchParams.get('id');
const isEdit = !!postId;
//폼 항목 여러개니까 일괄처리하려고 form이라는 하나의 객체로 모든 필드 관리
const [form, setForm] = useState<PostForm>({
title: '',
author: '',
password: '',
content: '',
});
useEffect(() => {
if (isEdit) {
// 수정 시 기존 게시글 데이터 가져오기
// 임시 데이터 (나중에 API 연동 시 제거)
setForm({
title: '기존 게시글 제목',
author: '기존 작성자',
password: '',
content: '기존 게시글 내용',
});
}
}, [isEdit]);
const handleSubmit = (event: React.FormEvent) => {
event.preventDefault();
// 게시글 작성/수정 로직 구현
router.push('/');
};
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
const { name, value } = e.target;
setForm((prev) => ({
...prev,
[name]: value,
}));
};
return (
....
);
}
react-hook-form : 폼 상태를 자동으로 관리하고, 유효성 검사도 처리해주는 라이브러리
https://velog.io/@boyeon_jeong/React-Hook-Form
[React Hook Form] react hook form 기본 예시 따라하기
🕐❗❕❓❔🔅⚠⛔❌⭕✔➕➖✖💣💰📔📖🔗🏆🔥⚡😀😎🤓😭😵😲😨😱😮😪😩❤🧡👀☠React Hook Form은 React 유효성 검사와 폼 관리를 단순화하는 강력한💣 라이브러리입니다. 이 라
velog.io
"use client";
import { useEffect } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import Link from "next/link";
import { useForm } from "react-hook-form";
import axios from "axios";
interface PostData {
title: string;
author: string;
password: string;
content: string;
}
export default function Write() {
const searchParams = useSearchParams();
const postId = searchParams.get("id");
const isEdit = !!postId;
const router = useRouter();
// react-hook-form 라이브러리 사용
// 자동 바인딩 + 유효성 검사 가능
const {
register,
handleSubmit,
setValue,
formState: { errors },
} = useForm<PostData>();
useEffect(() => {
if (isEdit && postId) {
const apiURL = "http://3.35.233.169:8080/swagger-ui/index.html#/";
const endpoint = "/~~~~"; // 버에 안들어가져서 모르겠네염
axios
// GET으로 폼 작성햇던 데이터 받아오기
.get(`${apiURL}${endpoint}/${postId}`)
.then((res) => {
const { title, author, password, content } = res.data;
setValue("title", title);
setValue("author", author);
setValue("content", password);
setValue("content", content);
})
// 요청 실패시 오류 처리
.catch((err) => {
console.error("폼 불러오기 실패:", err);
});
}
}, [isEdit, postId, setValue]); //isEdit, postId, setValue 중 하나가 변경될 때마다 실행
const onSubmit = async (data: PostData) => {
const apiURL = "http://3.35.233.169:8080/swagger-ui/index.html#/";
try {
if (isEdit && postId) {
//PUT으로 수정 시 덮어쓰기 해주기
await axios.put(`${apiURL}/posts/${postId}`, data);
alert("폼 수정완료");
} else {
// isEdit이 아닌 경우 (즉 작성하기일떄) POST 로 데이터 전송
await axios.post(`${apiURL}/posts`, data);
alert("폼 작성완료");
}
router.push("/"); // 메인으로 이동하기
} catch (error) {
console.error("요청 실패:", error);
}
// TODO: API 요청 처리 (axios.post 또는 axios.put)
router.push("/");
};
return (
....
);
}
취소 버튼 빼고... 상단 이전으로 버튼 추가
<Link href="/" className="text-blue-500 hover:underline mb-4 block">
← 이전으로
</Link>