-
Notifications
You must be signed in to change notification settings - Fork 26
[양재영] sprint9 #143
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
[양재영] sprint9 #143
The head ref may contain hidden characters: "Next-\uC591\uC7AC\uC601-sprint9"
Conversation
|
스프리트 미션 하시느라 수고 많으셨어요. |
| @@ -0,0 +1,56 @@ | |||
| const BASE_URL = `${process.env.NEXT_PUBLIC_BASE_URL}/items`; | |||
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.
items를 지워도 될 것 같아요 !
현재 itmes 외에도 이미지 업로드에 필요한 images API도 있는 것으로 보이는군요 😉
| const BASE_URL = `${process.env.NEXT_PUBLIC_BASE_URL}/items`; | |
| const BASE_URL = `${process.env.NEXT_PUBLIC_BASE_URL}`; |
위와 같이 사용해볼 수 있습니다 😆
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.
해당 파일은 index.tsx보다 index.ts 확장자가 더 낫겠군요 !
해당 파일은 jsx 문법을 사용하고 있지 않기에 .ts로 변경하셔도 무방합니다 😉
그럼 확장자만 봐도 JSX 파일인지 아닌지 구분할 수 있겠죠? 😆
| export async function patchData( | ||
| itemId: number, | ||
| updateData: Partial<{ name: string; isCompleted: boolean }> | ||
| ) { | ||
| try { | ||
| const response = await fetch(`${BASE_URL}/${itemId}`, { | ||
| method: "PATCH", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| }, | ||
| body: JSON.stringify(updateData), | ||
| }); | ||
| if (!response.ok) { | ||
| throw new Error("서버 요청 실패" + response.status); | ||
| } | ||
| const data = response.json(); | ||
| return data; | ||
| } catch (error) { | ||
| console.log("에러 발생", error); | ||
| } | ||
| } |
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.
Swagger 문서를 보면 다음과 같이 스키마의 타입을 알 수 있습니다:
해당 타입으로 다음과 같은 타입을 정의해볼 수 있겠군요 !
interface Item {
id: number;
tenantId: string
name: string;
memo: string;
imageUrl: string;
isCompleted?: boolean;
}그리고 요청 타입과 응답 타입을 정의해볼 수 있습니다 !
interface PatchTodoRequest extends Partial<Omit<TodoItem, 'id'>> {}
interface PatchTodoResponse extends TodoItem {}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.
(이어서) 그리고 API 함수에 다음에 요청과 응답 타입을 정의해볼 수 있습니다 😉
| export async function patchData( | |
| itemId: number, | |
| updateData: Partial<{ name: string; isCompleted: boolean }> | |
| ) { | |
| try { | |
| const response = await fetch(`${BASE_URL}/${itemId}`, { | |
| method: "PATCH", | |
| headers: { | |
| "Content-Type": "application/json", | |
| }, | |
| body: JSON.stringify(updateData), | |
| }); | |
| if (!response.ok) { | |
| throw new Error("서버 요청 실패" + response.status); | |
| } | |
| const data = response.json(); | |
| return data; | |
| } catch (error) { | |
| console.log("에러 발생", error); | |
| } | |
| } | |
| export async function patchData( | |
| itemId: number, | |
| updateData: PatchTodoRequest | |
| ): Promise<ApiResponse<PatchTodoResponse>> { | |
| try { | |
| const response = await fetch(`${BASE_URL}/${itemId}`, { | |
| method: "PATCH", | |
| headers: { | |
| "Content-Type": "application/json", | |
| }, | |
| body: JSON.stringify(updateData), | |
| }); | |
| if (!response.ok) { | |
| throw new Error(`서버 요청 실패: ${response.status}`); | |
| } | |
| const data: PatchTodoResponse = await response.json(); | |
| return { data }; | |
| } catch (error) { | |
| console.log("에러 발생", error); | |
| return { | |
| error: error instanceof Error ? error.message : "알 수 없는 오류가 발생했습니다" | |
| }; | |
| } | |
| } | |
이렇게 정의해두면 요청 타입과 응답 타입이 필요할 때 export 해볼 수 있으며 타입에 별칭이 있어 가독성도 향상될 수 있겠군요 !
| import plusIc from "@/assets/plus.svg"; | ||
| import Image from "next/image"; | ||
|
|
||
| export const Button = ({ handleSubmit }) => { | ||
| return ( | ||
| <button | ||
| onClick={handleSubmit} | ||
| className="w-[168px] border-2 border-slate-900 bg-slate-100 rounded-3xl px-5 py-2 shadow-md shadow-slate-800 items-center font-bold flex justify-center gap-2 text-slate-900" | ||
| > | ||
| <Image src={plusIc} width={16} height={16} alt="추가 아이콘" /> 추가하기 | ||
| </button> | ||
| ); | ||
| }; |
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.
(응용 / 더 나아가기) 해당 컴포넌트는 자칫 공통컴포넌트로 오해할 수 있겠군요.
src/components/ui/button.tsx 이름과 경로를 보더라도 해당 앱 어디서나 사용될 수 있는 공통컴포넌트로 오해될 수 있을 것 같아요.
두 가지 방법을 제안드리고 싶습니다 !
공통 컴포넌트를 진짜 만들어버리기
// components/common/Button.tsx
import { ButtonHTMLAttributes } from "react";
import clsx from "clsx";
interface CommonButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "primary" | "secondary" | "ghost"; // 예시로 작성했습니다 😉
}
export function Button({
children,
variant = "primary",
className,
...props
}: CommonButtonProps) {
const baseStyle =
"rounded-3xl font-bold flex items-center justify-center gap-2 transition-colors duration-150";
const variants = {
primary:
"bg-slate-100 text-slate-900 border-2 border-slate-900 shadow-md shadow-slate-800 hover:bg-slate-200",
secondary:
"bg-white text-slate-800 border border-slate-400 hover:bg-slate-100", // 예시로 작성했습니다 😉
ghost: "text-slate-600 hover:text-slate-800 hover:bg-slate-100", // 예시로 작성했습니다 😉
};
return (
<button
{...props}
className={clsx(baseStyle, variants[variant], className)}
>
{children}
</button>
);
}(이어서)
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.
두번째 방법: 컴포넌트 이름 바꾸기
정말 간단합니다 😉 그냥 이름만 바꿔줘도 될 것 같아요 !
| import plusIc from "@/assets/plus.svg"; | |
| import Image from "next/image"; | |
| export const Button = ({ handleSubmit }) => { | |
| return ( | |
| <button | |
| onClick={handleSubmit} | |
| className="w-[168px] border-2 border-slate-900 bg-slate-100 rounded-3xl px-5 py-2 shadow-md shadow-slate-800 items-center font-bold flex justify-center gap-2 text-slate-900" | |
| > | |
| <Image src={plusIc} width={16} height={16} alt="추가 아이콘" /> 추가하기 | |
| </button> | |
| ); | |
| }; | |
| import plusIc from "@/assets/plus.svg"; | |
| import Image from "next/image"; | |
| export const AddItemButton = ({ handleSubmit }) => { | |
| return ( | |
| <button | |
| onClick={handleSubmit} | |
| className="w-[168px] border-2 border-slate-900 bg-slate-100 rounded-3xl px-5 py-2 shadow-md shadow-slate-800 items-center font-bold flex justify-center gap-2 text-slate-900" | |
| > | |
| <Image src={plusIc} width={16} height={16} alt="추가 아이콘" /> 추가하기 | |
| </button> | |
| ); | |
| }; |
해당 컴포넌트는 특수 목적이 있는 버튼임을 명시하는 방법이 있습니다 !
| onChange={handleChange} | ||
| handleKeyDown={handleKeyDown} | ||
| /> | ||
| <Button handleSubmit={handleSubmit} /> |
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.
(이어서) 해당 코드를 다음과 같이 변경합니다:
| <Button handleSubmit={handleSubmit} /> | |
| <Button onClick={onClick} /> |
React.ButtonHTMLAttributes<HTMLButtonElement>에 이미 onClick 속성이 존재하므로 따로 props에 명시할 필요 없이 사용할 수 있습니다 😉
| extend: { | ||
| colors: { | ||
| slate: { | ||
| 100: "#F1F5F9", | ||
| 200: "#E2E8F0", | ||
| 300: "#CBD5E1", | ||
| 400: "#94A3B8", | ||
| 500: "#64748B", | ||
| 800: "#1E293B", | ||
| 900: "#0F172A", | ||
| }, | ||
|
|
||
| "accent-violet-600": "#7C3AED", | ||
| "accent-violet-100": "#DED9FE", | ||
| "accent-rose": "#4F3F5E", | ||
| "accent-lime": "#BEF264", | ||
| "accent-amber": "#92400E", | ||
| }, | ||
| fontFamily: { | ||
| sans: ["NanumSquare", "system-ui", "sans-serif"], | ||
| }, | ||
| }, | ||
| }, |
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.
크으 ~ 테며드셨군요 👍
테일윈드 참 편리하고 좋지요 👍 테일윈드 설정을 통해서 팔레트를 정의하셨군요. 훌륭합니다 👍
|
수고하셨습니다 재영님 ! 이번 심화 프로젝트에서도 재영님의 역량이 팀에 큰 힘이 될 것이라 확신합니다 😉 미션 수행하시느라 수고 많으셨습니다 ! |
요구사항
기본
스크린샷
멘토에게