Skip to content
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

[채종민] sprint10 #626

Conversation

JayChae
Copy link
Collaborator

@JayChae JayChae commented Jun 7, 2024

배포: https://6-sprint-mission-git-nextjs-sprint10-jaychaes-projects.vercel.app/?_vercel_share=FTXpQDu9iYCdhDZsaIXki8XUZrqUvIzj

요구사항

기본

  • 상품 등록 페이지 주소는 “/addboard” 입니다.

  • 게시판 이미지는 최대 한개 업로드가 가능합니다.

  • 각 input의 placeholder 값을 정확히 입력해주세요.

  • 이미지를 제외하고 input 에 모든 값을 입력하면 ‘등록' 버튼이 활성화 됩니다.

  • 회원가입, 로그인 api를 사용하여 받은accessToken을 사용하여 게시물 등록을 합니다.

  • ‘등록’ 버튼을 누르면 게시물 상세 페이지로 이동합니다.

  • 상품 상세 페이지 주소는 “/addboard/{id}” 입니다.

  • 댓글 input 값을 입력하면 ‘등록' 버튼이 활성화 됩니다.

  • 활성화된 ‘등록' 버튼을 누르면 댓글이 등록됩니다

심화

  • [x]
  • []

주요 변경사항

스크린샷

image

멘토에게

  • 아 커밋 나눠야 하는 데 또 깜빡했어요. 담 비션 때는 잘 나눠보도록 할게요
const postArticle: PostArticle = async ({ image, content, title }) => {
  try {
    const { data } = await axiosInstance.post<Response>(`articles`, {
      image,
      content,
      title,
    });
    return data;
  } catch (error) {
    console.error("APP ERROR: ", error);
    if (error instanceof Error) {
      throw new Error(`좋아요를 할 수 없습니다`);
    }
    throw new Error("알 수 없는 오류로 인해 좋아요를 할 수 없습니다.");
  }
};
에서 await axiosInstance.post<Response> 이렇게 하는  맞나요?
  1. post 요청 response는 받아서 확인하나요? 아니면 그냥 버리나요?

  2. post로 데이터 수정한 다음에 get api 함수로 화면 업데이트를 하나요(예를 들면 새로고침...)
    아니면 그냥 state만 살짝 바꿔주나요? -> 이 경우면 제가 작성한 글은 실시간 적용이 되는데
    다른 분들이 작성한 글은 실시간 적용이 안 되는 단점이 있는 것 같아요.

  • 셀프 코드 리뷰를 통해 질문 이어가겠습니다.

@JayChae JayChae requested a review from kiJu2 June 7, 2024 08:13
@JayChae JayChae self-assigned this Jun 7, 2024
@JayChae JayChae added the 매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다. label Jun 7, 2024
@kiJu2
Copy link
Collaborator

kiJu2 commented Jun 10, 2024

수고 하셨습니다 ! 스프리트 미션 하시느라 정말 수고 많으셨어요.
학습에 도움 되실 수 있게 꼼꼼히 리뷰 하도록 해보겠습니다.

1. 코드 관련

  • Axios 타입 정의를 잘 해주셨어요! 다만 해당 코드를 확인하니 'Response'가 중복되는 타입으로 보여요!
  • ArticleType를 import해서 사용하시면 더욱 좋을 것 같습니다!
  • 자세한 내용은 file에 코맨트 남겨 두었습니다.

2. post 요청 response는 받아서 확인하나요? 아니면 그냥 버리나요?

  • 요청을 받아서 사용하지 않는다면 성공 여부만 확인할 수도 있습니다.
  • 하지만 end point에서는 반환을 해주시는게 좋아요. 추후에 어떻게 사용될 지 모르니까요 ㅎㅎ

3. post로 데이터 수정한 다음에 get api 함수로 화면 업데이트를 하나요(예를 들면 새로고침...)
아니면 그냥 state만 살짝 바꿔주나요? -> 이 경우면 제가 작성한 글은 실시간 적용이 되는데
다른 분들이 작성한 글은 실시간 적용이 안 되는 단점이 있는 것 같아요.

  • 좋은 질문입니다! 종민님이 적용해 주신 방법은 '낙관적 업데이트'로 볼 수 있어요.
  • 어떤 방법이 가장 좋다고 말하기는 어려워요, 상황에 맞게 판단할 수 있다면 베스트!!

낙관적 업데이트란?

낙관적 업데이트(Optimistic Updates)는 웹 애플리케이션에서 사용자 경험을 개선하기 위해 사용되는 기술입니다. 이 기술은 사용자 인터페이스(UI)가 서버로부터 응답을 받기 전에 미리 업데이트되도록 합니다. 이를 통해 사용자는 즉각적인 피드백을 받고, 애플리케이션이 더 빠르고 반응성 있게 느껴집니다. 낙관적 업데이트는 특히 데이터 변경이 자주 발생하는 애플리케이션에서 유용합니다.

작동 원리
낙관적 업데이트는 다음과 같은 절차를 따릅니다:

1. 로컬 상태 업데이트:
사용자가 어떤 행동(예: 댓글 작성, 좋아요 클릭 등)을 수행하면, 애플리케이션은 즉시 로컬 상태를 업데이트하여 UI에 반영해요.

2. 서버 요청:
동시에 애플리케이션은 서버에 실제 요청을 보내요.

3. 서버 응답:
서버는 요청을 처리한 후 성공 또는 실패 응답을 반환받아요.

4. 상태 동기화:
서버 응답이 성공이면, 이미 로컬에서 업데이트된 상태를 그대로 유지합니다.
서버 응답이 실패하면, 로컬 상태를 이전 상태로 롤백하거나, 오류 메시지를 표시하는 등 적절한 처리를 수행합니다.

장점
즉각적인 피드백: 사용자가 작업을 수행했을 때 즉각적인 피드백을 받음으로써 애플리케이션의 반응성이 높아집니다.
향상된 사용자 경험: 사용자는 애플리케이션이 빠르고 매끄럽게 동작한다고 느끼게 됩니다.

단점
복잡한 구현: 서버 응답이 실패했을 때 상태를 롤백하는 등 오류 처리를 잘해야 합니다.
데이터 일관성 문제: 로컬 상태와 서버 상태 간의 일관성을 유지하는 것이 어려울 수 있습니다.

@kiJu2
Copy link
Collaborator

kiJu2 commented Jun 10, 2024

수고 정말 많으셨어요. 리뷰 중 궁금하신거 있으시면 사전 질의를 통해서 남겨주시거나 멘토링 미팅 때 질문주세요 ㅎㅎㅎ

@kiJu2 kiJu2 merged commit 9f4c90d into codeit-bootcamp-frontend:Next.js-채종민 Jun 10, 2024
Comment on lines +1 to 3
REACT_APP_API_URL = https://panda-market-api.vercel.app/

NEXT_PUBLIC_BASE_URL=https://panda-market-api.vercel.app/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.gitignore에 env파일을 추가해 주셨군요!

하지만 아직 github에서 확인되는 걸 보니 캐시를 지워줘야 할 것으로 보입니다 :)

  git rm .env --chached

gitignore에 .env 파일을 추가해도 commit history에 env파일이 남아있게 됩니다!

git에 env파일을 완전히 지우려면 추가 작업이 필요해요 😂
아래 블로그를 참고해 보시면 좋을 것 같아요!

[Git] 실수로 올린 env 삭제하기 (commit history까지 완전 삭제)

Comment on lines +10 to +22
interface Response {
createdAt: string;
updatedAt: string;
likeCount: number;
writer: {
id: number;
nickname: string;
};
image: string | null;
content: string;
title: string;
id: number;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

중복되는 코드(타입)를 하나의 파일에서 관리해 보면 어떨까요?!

ResponsegetArticle.ts 에서 사용한 타입과 중복되는 내용으로 보여요.😂

interface ArticleType {
  updatedAt: string;
  createdAt: string;
  likeCount: number;
  writer: {
    id: number;
    nickname: string;
  };
  image: string | null;
  content: string;
  title: string;
  id: number;
}

공통적으로 사용되는 타입은type.ts파일을 만들고 관리하면 좋을 것 같아요!
타입이 여러 곳에 중복되어 정의되어 있으면, 변경이 필요할 때마다 모든 정의를 일일이 수정해야 합니다. 타입을 하나의 코드로 관리하면 한 곳에서 수정하면 되므로 유지보수가 훨씬 용이합니다. 😊

const accessToken = localStorage.getItem("accessToken");
if (image) {
const imageUrl = await postImage({ image });
console.log(imageUrl);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

console는 pull request 전에 제거해 주시는 게 좋아요!

작업한 내용을 commit 하기 전에 불필요한 로깅은 지워주면 좋아요! 로그가 남으면 남을 수록 추 후 디버깅이 어려워집니다.. 하핳ㅎ

개인적인 팁 !

저는 다음과 같이 저만의 식별 $$과 같은 값을 앞에 두는 버릇이 있는데 크롬/VSCode에서 콘솔 검색할 때 편하더라구염

Suggested change
console.log(imageUrl);
console.log('$$ imageUrl: ', imageUrl);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그리고 add 할 때 -p 옵션을 줘보세요 !

git add . -p를 사용하게 되면 변경사항을 스테이징에 올릴 때 파일 내 코드 단위로 잘라서 올릴 수 있습니다 ! 상당히 유용하므로 히스토리를 신경쓰신다면 꼭 사용해보세요 😊

어떻게 사용하지?

git add . -p

Comment on lines +29 to +40
try {
const accessToken = localStorage.getItem("accessToken");
const { data } = await axiosInstance.post<Response>(
`articles/${articleId}/comments`,
{ content },
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
}
);
return data;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

토큰을 잘 넣어두셨군요 👍

아래는 axios의 메써드인 interceptors를 통하여 미들웨어로 인가를 처리하는 예제예요 ! 한 번 확인해보시고 적용하시는 것도 고려해보세요 😊😊😊

instance.interceptors.request.use(
  (config) => {
    const accessToken = localStorage.getItem('accessToken')?.replace(/"/gi, '');

    if (!accessToken) return config;
    config.headers.Authorization = accessToken;
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

instance.interceptors.response.use(
  (response) => {
    return response;
  },
  (error) => {
    alert(`ERROR: ${error.response.data.message} `);
    return Promise.reject(error);
  }
);

Comment on lines +11 to +20
return (
<Image
src={ic_heart}
alt="하트 버튼"
width={width}
height={height}
className="cursor-pointer"
onClick={onClick}
/>
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image 태그의 onClick

  • nextjs의 Image는 onClick을 지원하지 않아요! 참고자료
  • 만약 작동하지 않는 다면 아래와 같이 상위 요소로 감싸서 이용하실 수 있습니다 😊
Suggested change
return (
<Image
src={ic_heart}
alt="하트 버튼"
width={width}
height={height}
className="cursor-pointer"
onClick={onClick}
/>
);
return (
<button type="button" onClick={onClick}>
<Image
src={ic_heart}
alt="하트 버튼"
width={width}
height={height}
className="cursor-pointer"
/>
</button>
);

desktop: number;
tablet: number;
mobile: number;
}
type useSetNumOfItemsToShowType = (prop: propType) => number;
type useSetNumOfItemsToShowType = (prop: PropType) => number;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type은 파스칼 케이스 사용!

깜박 하신 것 같아요. 수정해 주시면 좋을 것 같습니다 =)

width: number;
height: number;
disabled: boolean;
children: string;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

children네이밍 개선!

  • 이 부분도 목적에 맞는 네이밍을 사용하면 좋을 것 같아요!
Suggested change
children: string;
buttonLabel: string;

Comment on lines +21 to +37
.fileInput {
display: none;
}

.btn_upload {
width: 28.2rem;
height: 100%;
background-color: var(--coolGray100);
border: none;
border-radius: 1.2rem;
cursor: pointer;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 1.2rem;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

styles을 잘 분리해 주셨어요! 굿 👍

  • 다만 표기법이 혼용된 부분은 일관되게 수정하시면 더욱 좋을 것 같습니다!
Suggested change
.fileInput {
display: none;
}
.btn_upload {
width: 28.2rem;
height: 100%;
background-color: var(--coolGray100);
border: none;
border-radius: 1.2rem;
cursor: pointer;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 1.2rem;
}
.file_input {
display: none;
}
.btn_upload {
width: 28.2rem;
height: 100%;
background-color: var(--coolGray100);
border: none;
border-radius: 1.2rem;
cursor: pointer;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 1.2rem;
}
  • 개인적인 생각으론 다음에는 클래스 표기를 Kebab Case로 하시는 것도 좋을 것 같아요 =)

font-size: 1.8rem;
font-weight: 700;
line-height: 2.1rem;
color: var(--coolGray800);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

컬러를 팔레트를 잘 사용해 주셨네요! 굿!

  • 별도로 팔레트를 선언하고 사용해 작성해 주신 부분 너무 좋아요 👍


interface NoContentSignProp {
image: StaticImageData;
children: string;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

children네이밍 개선!

  • 일반적으로 React.ReactNode로 사용되는 경우가 많아요!
  • 목적에 맞는 보다 직관적인 이름을 사용하면 혹을 것 같아요 =)
Suggested change
children: string;
label: string;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants