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

[김찬기] Sprint6 #222

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
e7bf589
feat: ProtectedRoute 컴포넌트 추가 및 상품등록 페이지에 적용
cksrlcks Nov 25, 2024
6f1ef49
feat: useForm hook 수정
cksrlcks Nov 25, 2024
36ba19c
feat: Chip 컴포넌트 작업 (공용)
cksrlcks Nov 25, 2024
8cbb035
feat: Tags List 컴포넌트 작업
cksrlcks Nov 25, 2024
18366b1
feat: Input 컴포넌트 개선 (textarea 추가)
cksrlcks Nov 25, 2024
028c1af
feat: Tag input 컴포넌트 작업
cksrlcks Nov 25, 2024
093a254
feat: useForm hook 수정
cksrlcks Nov 26, 2024
a92f5f8
feat: FileInput 컴포넌트 작업
cksrlcks Nov 26, 2024
04dac8d
feat: 상품추가 페이지 1차 작업 (통신없이 콘솔로만 데이터 찍히도록)
cksrlcks Nov 26, 2024
4aa9d2a
feat: 이미지 업로드 및 상품추가 api 호출 작업
cksrlcks Nov 26, 2024
6c08c56
feat: 상품추가 페이지 폼제출 작업
cksrlcks Nov 26, 2024
dc4855a
refactor: service error 객체 수정 (status도 받을수 있도록)
cksrlcks Nov 26, 2024
b006c7c
feat: auth context 개선
cksrlcks Nov 26, 2024
c0506ac
feat: 상품추가 페이지 개선
cksrlcks Nov 26, 2024
6d438e0
chore: 사용안하는 코드 제거
cksrlcks Nov 26, 2024
9508f24
feat: Alert 컴포넌트 작업
cksrlcks Nov 26, 2024
af0326a
feat: 상품추가 페이지 작업
cksrlcks Nov 26, 2024
5b03f7b
fix: Proctected Route에서 accesstoken을 검사하도록 변경
cksrlcks Nov 26, 2024
788fd6f
refactor: Field 컴포넌트 작업
cksrlcks Nov 26, 2024
cddd907
feat: useLocalArray 훅 작업 (최근검색어등에 사용)
cksrlcks Nov 26, 2024
99ec63f
feat: 최근검색어 컴포넌트 작업
cksrlcks Nov 26, 2024
44914fb
refactor: useAuth 컨텍스트 개선
cksrlcks Nov 26, 2024
9e04b3b
feat: 최근검색, 검색 인풋 개선
cksrlcks Nov 26, 2024
7517df8
refactor(mentor): 폴더명과 컴포넌트명 일치화 (Prodcut)
cksrlcks Nov 26, 2024
7466805
refactor(mentor): 변수명이 배열을 의미하도록 변경(activePathList로 변경)
cksrlcks Nov 26, 2024
4d728dc
refactor(mentor): Nav css내 오타수정
cksrlcks Nov 26, 2024
cf20418
refactor(mentor): Search 컴포넌트 개선
cksrlcks Nov 26, 2024
478d31d
refactor(mentor): 공용 Container 컴포넌트 이름 변경 (PageContainer로 변경)
cksrlcks Nov 26, 2024
f3f987d
refactor(mentor): useAsync hook 개선
cksrlcks Nov 27, 2024
8b0e53d
chore: 불필요한 파일 정리
cksrlcks Nov 27, 2024
ed0a767
refactor(mentor): Form Field Container 컴포넌트 이름 변경
cksrlcks Nov 27, 2024
ddb2d45
feat: useForm에서 배열요소를 다룰수 있도록 개선
cksrlcks Nov 27, 2024
58aa7ca
feat: TagsInput이 배열 값을 다루도록 변경
cksrlcks Nov 27, 2024
4c4acf0
feat: Tags 랜더링시 '#'기호 붙여서 랜더링하도록 수정
cksrlcks Nov 27, 2024
10c47d0
bug: TagsInput에서 한글 작성후 enter시 글자가 짤리는 현상 수정
cksrlcks Nov 27, 2024
0f6a269
chore: Textarea 컴포넌트내 불필요한 코드 정리
cksrlcks Nov 27, 2024
98b2291
feat: NumberInput 컴포넌트 작업
cksrlcks Nov 27, 2024
06f8666
fix: AddItem페이지 문구수정 (상품 소개)
cksrlcks Nov 27, 2024
1ac333f
feat: useForm에서 custom validation을 할 수 있도록 개선
cksrlcks Nov 27, 2024
e668c12
feat: NumberInput이 format형태를 prop으로 받아서 사용할 수 있도록 개선 (재사용성 높이기)
cksrlcks Nov 27, 2024
85602c6
chore: 안쓰는 임포트, 변수 코드 지우기
cksrlcks Nov 27, 2024
472eb29
refactor(mentor): items 페이지에 멘토링시간에 배운 분리 적용 (presentational & conta…
cksrlcks Nov 27, 2024
d49857a
refactor: useSingleFile hook추가, 이미지 업로드 컴포넌트 개선
cksrlcks Nov 27, 2024
19b69a7
chore: alias 수정
cksrlcks Nov 27, 2024
56121d6
chore: alias 수정 (임포트된곳 바르게 고치기)
cksrlcks Nov 27, 2024
4a271b8
refactor: form schema, message 분리
cksrlcks Nov 27, 2024
1560dd6
refactor: Field 컴포넌트 리팩토링
cksrlcks Nov 27, 2024
9ced152
refactor: usePagination, Pagination 컴포넌트 개선
cksrlcks Nov 27, 2024
eb6120d
refactor: 공용 Form 컴포넌트 추가
cksrlcks Nov 27, 2024
9e3f609
chore: auth context 파일명 변경
cksrlcks Nov 27, 2024
f64e5df
refactor: Search 인풋, 최근검색어, useLocalStorage개선
cksrlcks Nov 28, 2024
b34e60f
refactor: 프로젝트 폴더, 파일구조 변경 (멘토링 참고)
cksrlcks Nov 28, 2024
6644153
feat: 페이지네이션 기능 추가 (이전그룹, 다음그룹 넘기기)
cksrlcks Nov 28, 2024
6427f21
refactor: 최근검색관련 items 페이지안에서 쓰는 hook으로 분리
cksrlcks Nov 28, 2024
3f11986
refactor: useList 훅 개선, 전체상품페이지 개선
cksrlcks Nov 28, 2024
89e62c1
fix: ProductFilter scss 파일명 오타 수정
cksrlcks Nov 28, 2024
78806de
fix: usePagination 수정
cksrlcks Nov 28, 2024
f89e43a
refactor: 코드 정리
cksrlcks Nov 28, 2024
9c25a84
refactor: react router 수정
cksrlcks Nov 28, 2024
9d7f1d1
feat: Error 페이지에 router error 표시하기
cksrlcks Nov 28, 2024
d9185cf
refactor: 베스트상품도 전체상품과 동일한 api호출 함수로 변경
cksrlcks Nov 28, 2024
bf2d40b
feat: 태그 인풋 ux개선 및 keydown시 합성문자 해결
cksrlcks Nov 29, 2024
2d24cc0
chore: AllItemsPage, BestItemsPage 코드 정리
cksrlcks Nov 30, 2024
ec28bb5
style: 최근검색 모달 그림자 추가
cksrlcks Nov 30, 2024
8bd2e97
chore: README.md 수정
cksrlcks Nov 30, 2024
d8e2c08
feat: 로그인후 로그인, 회원가입페이지 접근시 items페이지로 이동 구현
cksrlcks Nov 30, 2024
7ccee03
chore: README.md 수정
cksrlcks Nov 30, 2024
6560fa0
fix: react router 경고 제거 (v7 future 관련 경고)
cksrlcks Nov 30, 2024
3bd6277
refactor: useSyncParams 작업
cksrlcks Nov 30, 2024
07917e8
bug: TagsInput에서 Enter시 폼제출 되는 현상 수정
cksrlcks Nov 30, 2024
497894a
refactor: searchparams를 바로 이용하도록 개선
cksrlcks Nov 30, 2024
ce75b23
refactor: usePageSize return 형태 수정
cksrlcks Dec 1, 2024
5e32e25
refactor: 이미지 썸네일 공용 컴포넌트 제작
cksrlcks Dec 1, 2024
0040bbb
style: 공용 썸네일추가건으로 인한 스타일 보정
cksrlcks Dec 1, 2024
6dbc364
fix: number input에 undefined가 못들어가도록 수정
cksrlcks Dec 1, 2024
f5f4499
fix: number input에 NaN이 나오는 현상 수정
cksrlcks Dec 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,40 @@ state 관리하고 있는 params과 usePageSize로 관리하는 pageSize의 변
- useList에서 보정을 하려면, pagination 훅에서 관리하는 값을 가져와야했고,
- usePageSize에서 보정을 하려면 List컴포넌트에서 관리하고 있는 params state의 정보와 관리하는 함수들을 가져와야했습니다.
- 최종적으로 내린 결론은, 통신쪽을 수정하여 이전 요청을 취소하고 통신을 하는 방향으로 수정을 했습니다.

#### useList vs useFetch vs useAsync

데이터를 받는 훅을 만들때, 처음에는 리스트에 특화된 훅을 만드려고 했는데 다른곳에서는 재사용하기 힘들어서
범용적인 데이터를 받는 훅을 만드는게 좋을것 같아서 고민을 했습니다.

1. 첫번째 시도(기존코드) (리스트형 데이터 패칭에 특화된 useList)

- 장점

- useList를 호출할때 넣어야되는 필요로하는 인자가 정해져 있어서 편리(눈에 잘보임)
- params 객체를 넘겨받아도 인자가 정해져있으니 구조분해하여 useEffect의 의존성배열에 넣기 수월

- 단점
- 하지만 모든 요청에 동일한 인자를 보내는건 아니므로 범용성이 떨어져보임
- 좀더 일반적인 함수로 바꿔보려고 두번째 시도인 useFetch를 생각

2. 두번째 시도 (데이터요청함수를 실행만 하고 그 함수에 보낼 인자들을 넘겨주기만 하는 useFetch)

- 장점
- 훅 자체는 요청함수, 인자들에대해 모르고 있어도 되어서 범용성이 좋은것 같음
- 단점
- 그대신 넘어가는 인자들을 객체로 보내는데 useMemo로 참조를 보정해줘야함(어떤게 올지 몰라서, 구조분해로 분리못함)
- 그리고 무슨 인자로 요청하는지는 파악이 안됨 (사용하는 입장에서)

3. 세번째 시도 (둘다 이용해볼까?)

- useList가 useFetch를 이용하면 안될까? 필요한곳에서 useFetch를 재사용도 가능짐
- useList가 받은 객체를 메모지이에션해서 useFetch로 넘겨주는 방식으로 작업했습니다.
- 효과 : useList에서 받아야하는 인자값을 나타낼수 있고, useFetch를 useList 뿐만 아니라 다른곳에서도 사용 가능

4. 네번째 마지막 시도 ㅜㅜ(useFetch와 useAsync를 쓰는 방법, 차이점)

- 생각해보니 useFetch는 '주소'를 받아서 fetch처리하는 훅으로 사용되어야할 것 같음 (구글링의 예제 코드들을 분석해봄)
- url주소 기반으로 처리하는 useFetch를 쓰게되면, 만약에 api url이 변경되거나 요청전 작업이 수정되면 수정하러 이곳저곳을 돌아다녀야 할 것 같음.
- 비동기 요청함수를 받아서 처리하는 훅으로 만들어둔 useAsync를 쓰는게 더 적합해보임
- 주소를 기반으로 fetch만을 처리하는 훅으로 useFetch를 수정하고 남겨두기로 결정
Copy link
Contributor

Choose a reason for hiding this comment

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

고민했던 것들 정리해서 기록하는 것 매우 좋아요~👍

Copy link
Contributor

@withyj-codeit withyj-codeit Dec 3, 2024

Choose a reason for hiding this comment

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

개인적으로 data fetching 하는 hook 하나 (다른 api콜 할 때도 사용하는 공용 hook),
data fetching 하는 hook을 사용해서 실제 서비스에 필요한 api 콜하고 데이터를 받고 필요한 데이터 정제 및 일부 필요한 기능이 들어있는 hook 하나 이렇게 분리해서 사용하는게 깔끔했었어요.

참고 링크는 이후에 다루게 되는 react-query의 예시인데 useQuery같이 api 콜에 필요한 기능을 가진 hook이 있고, 그리고 이걸 래핑해서 구현해서 사용하는 custom hook으로 분리하는 방식으로 사용하는 방식이 좋았어요.

물론 간단한 요청의 경우 data fetching 하는 hook을 바로 사용 하는 것도 괜찮은 옵션이라 생각해요.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

리액트쿼리 적용할때 참고해서 적용해보겠습니다!

  • api요청 함수를 서비스쪽에 모아두고 이것을 활용해서 데이터 패칭을 하려니까 좀 복잡해진것 같습니다.
  • 리액트라우터의 loader쪽에도 이 함수를 재사용하고 싶어서 분리하게 되었는데,
  • 리액트쿼리 같은 라이브러리들에서도 이 서비스 함수를 이용하는 방법도 알아보려고합니당

1 change: 0 additions & 1 deletion jsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@hooks/*": ["src/hooks/*"],
"@context/*": ["src/context/*"],
Expand Down
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"private": true,
"dependencies": {
"clsx": "^2.1.1",
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.28.0"
Expand Down
8 changes: 6 additions & 2 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { Outlet } from "react-router-dom";
import { AuthProvider } from "./context/AuthContext";
import { RouterProvider } from "react-router-dom";
import { router } from "./router";

export default function App() {
return (
<>
<Outlet />
<AuthProvider>
<RouterProvider router={router} />
</AuthProvider>
</>
);
}
4 changes: 4 additions & 0 deletions src/assets/img/icon/icon_double_arrow_left.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/assets/img/icon/icon_double_arrow_right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/img/icon/icon_error.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/assets/img/icon/icon_plus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/img/icon/icon_warn.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion src/assets/scss/base/_reset.scss
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ button {
img {
vertical-align: top;
}
input {
input,
textarea {
padding: 0;
margin: 0;
border: none;
Expand Down
1 change: 1 addition & 0 deletions src/assets/scss/common/_index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@forward "input";
38 changes: 38 additions & 0 deletions src/assets/scss/common/_input.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.field {
position: relative;

.field-box {
display: block;
width: 100%;
height: 5.6rem;
padding: 0 2.4rem;
border: 1px solid transparent;
border-radius: 12px;
background: var(--color-secondary-100);

&:focus,
&.valid {
border: 1px solid var(--color-primary-100);
outline: none;
}

&.error {
border: 1px solid var(--color-error);
outline: none;
}

&::placeholder {
color: var(--color-secondary-400);
}

&:has(~ button) {
padding-right: 5rem;
}
}

textarea.field-box {
height: 28.2rem;
padding: 2.4rem;
resize: none;
}
}
1 change: 1 addition & 0 deletions src/assets/scss/style.scss
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
@use "base";
@use "common";
5 changes: 0 additions & 5 deletions src/components/Container/index.jsx

This file was deleted.

12 changes: 12 additions & 0 deletions src/components/Field/Error.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import styles from "./Error.module.scss";

export function Error({ error }) {
if (!error) {
return null;
}
return (
<div className={styles["item-error"]}>
{error || "오류가 발생했습니다."}
</div>
);
}
7 changes: 7 additions & 0 deletions src/components/Field/Error.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.item-error {
margin-top: 0.8rem;
padding-left: 1.6rem;
font-size: 1.4rem;
font-weight: 600;
color: var(--color-error);
}
15 changes: 15 additions & 0 deletions src/components/Field/FieldItem.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import styles from "./FieldItem.module.scss";

export function FieldItem({ children }) {
return <div className={styles["form-item"]}>{children}</div>;
}

function Label({ htmlFor, children }) {
return (
<label className={styles["item-label"]} htmlFor={htmlFor}>
{children}
</label>
);
}

FieldItem.Label = Label;
26 changes: 26 additions & 0 deletions src/components/Field/FieldItem.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@use "@assets/scss/base/mixins";

.form-item {
margin-bottom: 2.4rem;
position: relative;

@include mixins.mobile {
margin-bottom: 1.6rem;
}

.item-label {
display: inline-block;
margin-bottom: 1.6rem;
font-size: 1.8rem;
font-weight: 700;

@include mixins.mobile {
margin-bottom: 0.8rem;
font-size: 1.4rem;
}
}

.item-field {
position: relative;
}
}
13 changes: 13 additions & 0 deletions src/components/Field/Form.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Alert, LoadingSpinner } from "@components/ui";

export function Form({ isLoading, error, onSubmit, children }) {
return (
<>
{isLoading && <LoadingSpinner />}
{error && (
<Alert mode="error">{error.message || "오류가 발생했습니다."}</Alert>
)}
<form onSubmit={onSubmit}>{children}</form>
</>
);
}
55 changes: 55 additions & 0 deletions src/components/Field/ImageUpload.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import useSingleFile from "@hooks/useSingleFile";
import { Thumbnail } from "@components/ui";
import { Error } from "@components/Field";
import iconPlus from "@assets/img/icon/icon_plus.svg";
import styles from "./ImageUpload.module.scss";

const LIMIT_SIZE_MB = 2;

export function ImageUpload({
error,
value,
id,
name,
onChange,
placeholder = "이미지 등록",
}) {
const { fileProps, fileError, handleRemove, preview } = useSingleFile({
name,
value,
accept: "image/*",
limiSize: LIMIT_SIZE_MB,
onChange: (file) => onChange(name, file),
errorMessage: {
max: "이미지 등록은 최대 1개까지 가능합니다.",
accept: "이미지 파일만 업로드 가능합니다.",
},
});

// 두가지 에러 동시에 보내려고 문자열로 합침
const fileInputError = [fileError, error].filter((err) => err).join(" / ");

return (
<>
<div className={styles["thumbnail-list"]}>
<label className={styles["upload-button"]}>
<span className={styles["upload-label"]}>
<img src={iconPlus} alt="이미지 업로드" />
{placeholder}
</span>
<input id={id} name={name} className="a11y" {...fileProps} />
</label>
<div className={styles.preview}>
{preview && (
<Thumbnail
src={preview}
alt="상품 이미지 등록"
onRemove={handleRemove}
/>
)}
</div>
</div>
<Error error={fileInputError} />
</>
);
}
41 changes: 41 additions & 0 deletions src/components/Field/ImageUpload.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
.thumbnail-list {
display: flex;
gap: 2.4rem;
}

.upload-button {
overflow: hidden;
position: relative;
display: block;
width: 100%;
max-width: 28.2rem;
border-radius: 1.6rem;
background: var(--color-secondary-100);
cursor: pointer;

&:before {
content: "";
display: block;
width: 100%;
height: 0;
padding-bottom: 100%;
}

.upload-label {
position: absolute;
left: 0;
top: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1.3rem;
width: 100%;
height: 100%;
color: var(--color-secondary-400);
}
}

.preview {
max-width: 28.2rem;
}
Loading
Loading