-
Notifications
You must be signed in to change notification settings - Fork 77
[고한샘] sprint10 #663
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
The head ref may contain hidden characters: "Next.js-\uACE0\uD55C\uC0D8-sprint10"
[고한샘] sprint10 #663
Changes from 1 commit
87e3f15
1472169
671d4d5
14baca2
8d163dd
cf2e3df
398ac6c
a04698a
8f535bd
921aec0
f56d696
2ee994e
d80a89a
5d76a22
6f12196
6cdee27
af57418
c0b2b55
c5cd127
069ebed
c59c0eb
365a414
b690f65
d3bb2bb
eb445b0
b3d39fd
fbb8fcf
270af41
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,4 +11,5 @@ | |
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| border: none; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,9 @@ | ||
| import styles from "@/components/BlueButton.module.css"; | ||
|
|
||
| export default function BlueButton({ children }) { | ||
| return <div className={styles.write}>{children}</div>; | ||
| export default function BlueButton({ type = "", children }) { | ||
| return ( | ||
| <button type={type} className={styles.write}> | ||
| {children} | ||
| </button> | ||
| ); | ||
| } | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| import BlueButton from "@/components/BlueButton"; | ||
| import axios from "@/lib/axios"; | ||
| import Image from "next/image"; | ||
| import { useRouter } from "next/router"; | ||
| import { useEffect, useState } from "react"; | ||
|
|
||
| export function UserProfile({ article = {} }) { | ||
| return ( | ||
| <div> | ||
| <Image | ||
| src="/icon/profile-login-icon.png" | ||
| alt="user profile" | ||
| width={24} | ||
| height={24} | ||
| priority | ||
| /> | ||
| <span>{article.writer?.nickname}</span> | ||
| <span>{article.createdAt}</span> | ||
| <span>하트</span> | ||
| <span>{article.likeCount}</span> | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| export function ActicleItem({ article = {} }) { | ||
| return ( | ||
| <div className=""> | ||
| <h3>{article.title}</h3> | ||
| <UserProfile article={article} /> | ||
| <p>{article.content}</p> | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| export function CommentForm() { | ||
| return ( | ||
| <form> | ||
| <h4>댓글 달기</h4> | ||
| <label htmlFor="content"></label> | ||
| <textarea | ||
| id="content" | ||
| name="content" | ||
| placeholder="댓글을 입력해주세요." | ||
| /> | ||
| <BlueButton type="submit">등록</BlueButton> | ||
| </form> | ||
| ); | ||
| } | ||
|
|
||
| export function CommentItem({ comments }) { | ||
| return ( | ||
| <> | ||
| <p>{comments[0]?.content}</p> | ||
| <UserProfile /> | ||
| <Image | ||
| src="/icon/kebab-icon.png" | ||
| alt="kebab" | ||
| width={24} | ||
| height={24} | ||
| priority | ||
| /> | ||
| </> | ||
| ); | ||
| } | ||
|
|
||
| export function CommentList({ comments = [] }) { | ||
| return ( | ||
| <> | ||
| <CommentItem comments={comments} /> | ||
| </> | ||
| ); | ||
| } | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. export function CommentList({ comments = [] }) {
return (...와 같이 선언과 반환 사이에 아무런 로직이 들어있지 않은 컴포넌트들은 한번쯤 고민해보실 필요가 있을것 같아요 컴포넌트를 나누는 이유에는 여러 이유가 있을 수 있습니다. 만약 스스로 생각했을때 명확한 이유가 딱히 보이지 않는다면,
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 그리고 따로 만든 컴포넌트들은 왠만하면 다른 파일로 구분해주시는게 좋을것 같네요 최대한 pages내부의 파일에는 해당 파일에 대한 |
||
|
|
||
| export default function Article() { | ||
| const router = useRouter(); | ||
| const { query } = router; | ||
| const id = query["id"]; | ||
| const [article, setArtcle] = useState({}); | ||
| const [comments, setComments] = useState([]); | ||
|
|
||
| async function getArticle(articleId) { | ||
| if (!articleId) return; | ||
| const res = await axios.get(`/articles/${articleId}`); | ||
| const nextArticle = res.data; | ||
| setArtcle(nextArticle); | ||
| } | ||
| async function getComments(articleId) { | ||
| if (!articleId) return; | ||
| const res = await axios.get(`/articles/${articleId}/comments?limit=5`); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. const res = await axios.get(`/articles/${articleId}/comments`, params: {
limit: 5
});axios를 사용하신다면 위와같이 searchParam을 객체로 뺄 수 있어요 ㅎ |
||
| const nextComments = res.data.list; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. const nextComments = res.data.list;과 같이 axios결과값을 한번더 변수에 할당하는건 불필요해 보입니다 ㅎ 그리고 axios가 반환하는 data에는 비동기 함수의 결과값이 담기는데요, |
||
| setComments(nextComments); | ||
| } | ||
|
|
||
| useEffect(() => { | ||
| if (id) { | ||
| getArticle(id); | ||
| getComments(id); | ||
| } | ||
| }, [id]); | ||
| return ( | ||
| <> | ||
| <ActicleItem article={article} /> | ||
| <CommentForm /> | ||
| {!comments ? ( | ||
| <p>댓글이 없습니다.</p> | ||
| ) : ( | ||
| <CommentList comments={comments} /> | ||
| )} | ||
| </> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import BlueButton from "@/components/BlueButton"; | ||
| import { useRouter } from "next/router"; | ||
|
|
||
| export default function AddBoard() { | ||
| const router = useRouter(); | ||
| const { articleId } = router.query; | ||
| console.log(articleId); | ||
|
|
||
| return ( | ||
| <form> | ||
| <div> | ||
| <h2>게시글 쓰기</h2> | ||
| <BlueButton type="submit">등록</BlueButton> | ||
| </div> | ||
| <label htmlFor="title">*제목</label> | ||
| <input | ||
| type="text" | ||
| id="title" | ||
| name="title" | ||
| placeholder="제목을 입력해주세요" | ||
| /> | ||
| <label htmlFor="content">*내용</label> | ||
| <textarea id="content" name="content" placeholder="내용을 입력해주세요" /> | ||
| <label htmlFor="imageUpload">이미지</label> | ||
| <input | ||
| type="file" | ||
| id="imageUpload" | ||
| name="imageUpload" | ||
| accept="image/*" | ||
| placeholder="이미지 등록" | ||
| /> | ||
| </form> | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
타입스크립트를 사용한다면 타입을 꼭 지정해주세요!