-
Notifications
You must be signed in to change notification settings - Fork 44
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
[김현서] Week12 #385
The head ref may contain hidden characters: "part2-\uAE40\uD604\uC11C-week12"
[김현서] Week12 #385
Conversation
수고 하셨습니다 ! 위클리 미션 하시느라 정말 수고 많으셨어요. |
기능을 11주차 브랜치에서 작업하다가 나중에 옮겨서 몇 개의 commit이 반영되지 않았습니다.헙.. 그렇군요 넵넵 ! VSCode상에서 타입스크립트 관련 오류는 나지 않는데 아직 어떻게 실행해봐야할지 잘 모르겠어서 맞게 작성한 건지는 잘 모르겠습니다..!심화 기능 중 푸터가 시작되는 지점에서 링크 추가하기 영역이 다시 보이지 않게하는 부분은 구현하지 못하였습니다. 그렇군요 !! 타입스크립트 코드 유심히 보면서 코드리뷰 해보겠습니다 ! 😊 |
interface CustomButtonProps { | ||
onClick: () => void; | ||
icon: string; | ||
text: string; | ||
} | ||
|
||
const CustomButton = ({ onClick, icon, text }: CustomButtonProps) => { |
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.
React에서 제공하는 HTML type
을 사용해보시는건 어떨까요?
다음과 같이 리액트에서 제공하는 Attributes를 사용할 수도 있습니다:
import cn from 'classnames';
import { ButtonHTMLAttributes } from 'react';
interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary' | 'none';
}
export default function MelonButton({ className, variant, ...rest }: Props) {
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.
현서님 코드에 적용하면 다음고 같이 해볼 수 있어요 😊
interface CustomButtonProps { | |
onClick: () => void; | |
icon: string; | |
text: string; | |
} | |
const CustomButton = ({ onClick, icon, text }: CustomButtonProps) => { | |
interface CustomButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> { | |
// onClick: () => void; ⭐️ 이미 `ButtonHTMLAttributes`에 정의된 타입 | |
icon: string; | |
// text: string; ⭐️ 이미 `ButtonHTMLAttributes`에 정의된 타입 | |
} | |
const CustomButton = ({ onClick, icon, children }: CustomButtonProps) => { |
import styled from "styled-components"; | ||
|
||
const StyledAllButton = styled.button` | ||
const StyledAllButton = styled.button<{ active: boolean }>` |
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.
스타일 컴포넌트도 제네릭으로 타입을 주셨군요 !!! 👍👍👍
interface ButtonProps extends StyledButtonProps { | ||
text?: string; | ||
onClick?: () => void; | ||
} |
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.
해당 컴포넌트 타입도 ButtonHTMLAttributes<HTMLButtonElement>
를 활용해볼 수 있을 것 같아요 !
interface ButtonProps extends StyledButtonProps { | |
text?: string; | |
onClick?: () => void; | |
} | |
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> { | |
type: // 기존 `StyledButtonProps`에 있던 값 | |
} |
createdAt?: string; | ||
created_at?: string; | ||
url: string; | ||
title?: string; | ||
description?: string; | ||
imageSource?: string; | ||
image_source?: string; |
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에서 받아올 때 두가지 키로 내려오기 때문에 이렇게 한 것 같군요.
이럴 경우 하나의 키로 보장받을 수 있도록 지정하는게 좋습니다:
createdAt?: string; | |
created_at?: string; | |
url: string; | |
title?: string; | |
description?: string; | |
imageSource?: string; | |
image_source?: string; | |
createdAt?: string; | |
url: string; | |
title?: string; | |
description?: string; | |
imageSource?: string; |
백엔드에 요청하여 스네이크 케이스와 카멜 케이스에 대해 요청을 주는 것이 좋겠으나, 현재 상황에서는 어려워보이니 앱 내부에서 조정을 해야할 것 같아요.
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 호출 부에서 하나의 키로 보장받을 수 있게 노멀라이징을 해주면 됩니다 !
노멀라이징: 서로 다른 feature의 크기를 통일하기 위해서 크기를 변환 · 모두 동일한 크기 단위로 비교하기 위해 값을 변환하는 것.
다음과 같은 어댑터 패턴을 활용해볼 수 있어요:
어댑터 패턴?
// API로부터 받은 데이터 형태를 나타내는 타입들
type ApiResponse = {createdAt: Date} | {created_at: Date};
// 프론트엔드에서 사용할 데이터 형태
type User = {
createdAt: Date;
};
// 어댑터 함수
function adaptUser(data: ApiResponse): User {
return {
createdAt: 'createdAt' in data ? data.createdAt : data.created_at,
};
}
async function fetchUser(): Promise<User> {
const res = await fetch('/user');
const data: ApiResponse = await res.json();
return adaptUser(data); // 변환된 데이터 반환
}
const CardList = ({ isFolderPage }: CardListProps) => { | ||
const { data: folderData, isLoading } = useFolderList(); | ||
|
||
if (isLoading) return <div>Loading...</div>; | ||
if (!folderData) return null; | ||
|
||
const folderId: string = ""; |
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.
다음과 같이 타입 추론을 해서 코드를 더욱 간결하게 작성할 수 있습니다 😊:
const CardList = ({ isFolderPage }: CardListProps) => { | |
const { data: folderData, isLoading } = useFolderList(); | |
if (isLoading) return <div>Loading...</div>; | |
if (!folderData) return null; | |
const folderId: string = ""; | |
const CardList = ({ isFolderPage }: CardListProps) => { | |
const { data: folderData, isLoading } = useFolderList(); | |
if (isLoading) return <div>Loading...</div>; | |
if (!folderData) return null; | |
const folderId = ""; |
<SearchBar /> | ||
<S.CardContainer> | ||
{folderData.folder.links.map((link: any) => ( | ||
<Card key={link.id} link={link} isFolderPage={isFolderPage} /> |
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.
굳굳 ! 매우 적절한 key
군요 😊
closeModal: () => {}, | ||
}); | ||
|
||
const modalReducer = (state: ModalState, action: Action): ModalState => { |
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.
헙 !! reducer
를 활용하다니 !
정말 잘 사용하고 계시군요 ! 멋져요 현서님
} | ||
}; | ||
|
||
export const ModalProvider = ({ children }: { children: ReactNode }) => { |
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 { LinkData, fetchLinkData } from "../../services/fetchFolderLinksData"; | ||
|
||
export type FolderId = number | string | null; |
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.
FolderId
는 여러 파일/컴포넌트에서 사용될 것 같군요.
Folder
엔티티 type
을 지정하는 객체 타입을 만들어서 관리하는 것도 좋을 것 같아요. 예를 들면 Folder['id']
와 같이요 !
이는, types/folder.type.ts
등으로 만들어볼 수 있습니다. 😊
다음은 설명을 위해서 user
타입으로 Props에 적용한다면 어떻게 할까? 라는 관점에서 작성해본 코드예요.
/types/user.type.ts
interface IUser {
id: number;
created_at?: string;
createdAt?: string;
updated_at?: string;
url: string;
description: string;
image_source?: string;
imageSource?: string;
folder_id: number;
}
// interface CreateUser extends Pick<IUser, 'something'> {} ;
// interface SampleUser extends Pick<IUser, 'something'> {};
그리고 다음은 Props예요.
interface AvatarProps extends Pick<IUser, 'id' | 'imageSource'> {}
function Avatar({ id, imageSource }: AvatarProps) {}
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.
또한, 컴포넌트 파일에서 Props
외에 타입을 export
하는 경우는 드뭅니다 ! 😊
|
||
export type FolderId = number | string | null; | ||
|
||
const Folder = ({ folderId }: { folderId: FolderId }) => { |
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.
다른 컴포넌트와 마찬가지로 Props
타입을 만들어보는게 어떨까요?
const Folder = ({ folderId }: { folderId: FolderId }) => { | |
const Folder = ({ folderId }: FolderProps) => { |
정말 수고 많으셨어요 현서님 ...!! 전 주강사로 토요일에 항상 상주하고 있으니, 도움 필요하시면 언제든 방문해주세요 ㅎㅎㅎ |
요구사항
기본
심화
주요 변경사항
멘토에게