Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
b2e37bd
reset
hanseulhee Oct 10, 2023
6f8bbb0
Merge branch 'codeit-bootcamp-frontend:main' into main
hanseulhee Oct 10, 2023
e11e25f
fix: 머지 후 브랜치 삭제 github action 수정
hanseulhee Oct 10, 2023
212e864
env: workflows 폴더로 이동
hanseulhee Oct 10, 2023
4dc5dd0
Merge pull request #237 from hanseulhee/fix-github-actions
withyj-codeit Nov 6, 2023
ddb35a8
feat: 헤더, 상품 추가
gracelee5 Apr 11, 2024
644200d
feat: 상품 정렬 기능 추가
gracelee5 Apr 11, 2024
b8b97b0
style: 드롭다운 디자인 적용, 검색, 상품 등록, 드롭다운 위치 조정
gracelee5 Apr 11, 2024
c4dbe93
feat: navigate(/additem) 추가
gracelee5 Apr 11, 2024
2251cec
Merge branch 'codeit-bootcamp-frontend:main' into React-이경원-sprint5
gracelee5 Apr 12, 2024
bfbdec2
Merge branch 'React-이경원-sprint5' of https://github.com/gracelee5/6-Sp…
gracelee5 Apr 12, 2024
a8182ee
babel plugin impory issue
gracelee5 Apr 12, 2024
1ecb2b0
browserlist update
gracelee5 Apr 12, 2024
d145418
update: sortedItems state 삭제
gracelee5 Apr 12, 2024
a993960
feat : 상품 등록 페이지 이동
gracelee5 Apr 18, 2024
327648c
상품 등록 페이지 디자인, 파일 선택 기능 구현
gracelee5 Apr 18, 2024
24284d6
style: 이미지 등록버튼 디자인
gracelee5 Apr 18, 2024
4d6001d
feat: 버튼 활성화 기능 추가
gracelee5 Apr 19, 2024
6ca4142
style: 상품 등록 페이지 태블릿 사이즈 디자인
gracelee5 Apr 19, 2024
9b7b75d
feat: useCallback 추가
gracelee5 Apr 19, 2024
23c8847
feat: 로고 버튼 누르면 페이지 이동
gracelee5 Apr 19, 2024
3f054ad
feat: 멘토 리뷰 피드백 적용
gracelee5 Apr 19, 2024
7d6cf75
style: 이미지 등록 + 위치 변경
gracelee5 Apr 19, 2024
cc0bb7c
feat: 피드백 반영
gracelee5 Apr 25, 2024
c220d80
feat: 상품 상세페이지 (상품 정보)
gracelee5 Apr 25, 2024
62d72fa
feat: 상품 상세페이지 태그 기능 추가
gracelee5 Apr 26, 2024
d0c318c
feat: 댓글 기능 추가
gracelee5 Apr 26, 2024
f6a2b54
feat: 베스트 상품 고정
gracelee5 Apr 26, 2024
df81b03
feat: 상품 등록하기 태그 기능 추가
gracelee5 Apr 26, 2024
09fbd90
feat: 버튼 활성화 기능 추가
gracelee5 Apr 26, 2024
3311d64
Readme 삭제
gracelee5 Apr 26, 2024
c44727f
eslint 오류 삭제
gracelee5 Apr 26, 2024
3d8ae12
eslint 오류 제거
gracelee5 Apr 26, 2024
2c503c3
feat: typescript로 변경
gracelee5 May 23, 2024
dff82dd
fix: 빌드할 수 있도록 오류 수정
gracelee5 May 23, 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
52 changes: 29 additions & 23 deletions package-lock.json

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

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^29.5.12",
"@types/node": "^20.12.12",
"@types/react": "^18.3.2",
"@types/react-dom": "^18.3.0",
"axios": "^1.6.8",
"path-browserify": "^1.0.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.22.3",
"react-scripts": "5.0.1",
"styled-components": "^6.1.8",
"typescript": "^5.4.5",
"web-vitals": "^2.1.4"
},
"scripts": {
Expand Down
File renamed without changes.
15 changes: 10 additions & 5 deletions src/components/CommentInput.js → src/components/CommentInput.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import React, { useState } from "react";
import React, { useState, ChangeEvent } from "react";
import styled from "styled-components";
function CommentInput() {
const [comment, setComment] = useState("");

const handleInputChange = (event) => {
interface RegisterButtonProps {
isEnabled: boolean;
}

function CommentInput(): JSX.Element {
const [comment, setComment] = useState<string>("");
Copy link
Collaborator

Choose a reason for hiding this comment

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

제네릭을 활용하셨네요 👍
다만 initialState로 "" 을 전달하셨기 때문에, 제네릭없이도 string으로 잘 추론됩니다. 그걸 활용하시는 편이 좋습니다.

  • useState의 타입정의를 보면, 첫 인자의 타입이 추론되게 하여 편하게 사용할 수 있게 하려는 의도를 엿볼 수 있습니다. (첫 인수인 initialState의 타입으로 타입S를 추론)
    function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
  • 타입추론이 잘된다면 명시하지않는게 TS를 효과적으로 활용하는 방법이라고 알려져있습니다 - 이펙티브타입스크립트


const handleInputChange = (event: ChangeEvent<HTMLTextAreaElement>): void => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍
참고로, 이렇게 하셔도 간결하겠네요. 함수를 참조하는 변수 handleInputChange 자체에 타입을 지정해줄 수 있습니다

  const handleInputChange: ChangeEventHandler<HTMLTextAreaElement> = (event) => {
    setComment(event.target.value);
  };

setComment(event.target.value);
};

Expand Down Expand Up @@ -65,7 +70,7 @@ const InputArea = styled.textarea`
}
}
`;
const RegisterButton = styled.button`
const RegisterButton = styled.button<RegisterButtonProps>`
Copy link
Collaborator

Choose a reason for hiding this comment

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

A컴포넌트 구현에 바로위애 A컴포넌트의 인터페이스가 작성되는게 자연스러운 패턴으로 알고 있습니다
RegisterButtonProps 를 RegisterButton 위 라인에 두는 걸 제안드려요

display: flex;
flex-direction: row;
justify-content: center;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,16 @@ import axios from "axios";
import noneComments from "../images/noneComments.svg";
import dots from "../images/3dots.svg";

interface Comment {
id: number;
content: string;
image: string;
nickname: string;
updatedAt: string;
}

function CommentList() {
const [comments, setComments] = useState(null);
const [comments, setComments] = useState<Comment[]>([]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

const { productId } = useParams();

const getComments = async (productId) => {
Expand Down
19 changes: 14 additions & 5 deletions src/components/FileInput.js → src/components/FileInput.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { useEffect, useRef, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import styled from "styled-components";
import X from "../images/ic_X.svg";
import plus from "../images/ic_plus.svg";
function FileInput({ name, value, initialPreview, onChange }) {

interface FileInputProps {
name: string;
value: File | null;
initialPreview?: string;
onChange: (name: string, nextName: string | null) => void;
}
function FileInput({ name, value, initialPreview, onChange }: FileInputProps) {
const [preview, setPreview] = useState(initialPreview);
const inputRef = useRef();
const inputRef = useRef<HTMLInputElement>(null);
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

read-only로 안전하게 사용하셨군요.

useRef는 첫 인자를 null로 전달하면 read-only가 되는 특징이 있습니다. useRef를 cmd를 누른채로 클릭해서 타입선언을 확인해보세요 😄

2024-05-26.10.46.46.mov


const handleChange = (e) => {
const nextValue = e.target.files[0];
Expand Down Expand Up @@ -43,8 +50,10 @@ function FileInput({ name, value, initialPreview, onChange }) {
<InputText>이미지 등록</InputText>
</InputWrapper>
<Container1>
{value && <Image src={preview} alt="이미지 등록"></Image>}
{value && <Delete onClick={handleClearClick} src={X}></Delete>}
<>
{value && <Image src={preview} alt="이미지 등록"></Image>}
{value && <Delete onClick={handleClearClick} src={X}></Delete>}
</>
</Container1>
</Container>
);
Expand Down
File renamed without changes.
31 changes: 23 additions & 8 deletions src/components/TagInput.js → src/components/TagInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,47 @@ import React, { useState } from "react";
import styled from "styled-components";
import DeleteIcon from "../images/ic_X_gray.svg";

const InputTag = ({ tags, setTags, setIsTagsEmpty }) => {
interface TagInputProps {
tags: string[];
setTags: React.Dispatch<React.SetStateAction<string[]>>;
Comment on lines +5 to +7
Copy link
Collaborator

Choose a reason for hiding this comment

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

인터페이스는 TagInput가 어떤 컴포넌트인지 설명해줍니다.
이 부분을 보면, setTags를 통해 상위에서 받는 tags를 어떤방식으로든 수정할 수 있어보입니다.

조금 더 TagInput컴포넌트의 역할을 드러내려면, 또는 TagInput이 할 수 있는 동작을 제한하려면 이렇게 바꿔 볼 수 있겠죠.

interface TagInputProp{
  tags: stirng[];
  addTag: (tagName: string) => void;
  removeTag: (tagIndex: number) => void;
}

그럼 이 외부에서 선언만 보고도, TagInput이 tags를 무엇으로든 set할 수 있기보단, 추가/삭제를 하는 기능이 있다는 걸 알 수 있습니다. ( 그렇게 되면, 사실 Tag"Input" 이라는 이름이 안어울린다는 사실도 더 잘 보이게 되죠. 그리고나서 구현을 보면, input과 list를 같이 가지고 있고요 - 시각적으로는 input에 들어가있을지라도요 -.

무엇을 하는 컴포넌트인지를 더 잘 드러내면 네이밍, 코드파악, 컴포넌트분리, 리팩토링, 버그수정에 도움이 됩니다

setIsTagsEmpty?: React.Dispatch<React.SetStateAction<boolean>> | undefined;
Copy link
Collaborator

Choose a reason for hiding this comment

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

전달하는 곳이 없어서 제거해도되겠네요. 이런 부분에서도 ?를 지워봤을때, 타입이 깨지는지 확인하고, 어디서 어떻게 사용하는지, 사용할 필요가 없는지 확인하면서 타입체크의 장점을 누릴 수 있습니다

placeholder?: string;
}
const TagInput = ({
tags,
setTags,
setIsTagsEmpty,
placeholder,
}: TagInputProps) => {
const [inputValue, setInputValue] = useState("");

const handleInputChange = (e) => {
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
};

const handleInputKeyDown = (e) => {
const handleInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter" && inputValue.trim() !== "") {
setTags([...tags, inputValue.trim()]);
e.preventDefault();
setInputValue("");
setIsTagsEmpty(false);
if (setIsTagsEmpty) {
setIsTagsEmpty(false);
}
}
};

const handleTagDelete = (index) => {
const newTags = [...tags];
newTags.splice(index, 1);
setTags(newTags);
setIsTagsEmpty(newTags.length === 0);
if (setIsTagsEmpty) {
setIsTagsEmpty(newTags.length === 0);
}
};

return (
<InputTagContainer>
<TagInput
<InputTag
type="tag"
value={inputValue}
onChange={handleInputChange}
Expand All @@ -54,7 +69,7 @@ const InputTagContainer = styled.div`
align-items: flex-start;
`;

const TagInput = styled.input`
const InputTag = styled.input`
Copy link
Collaborator

Choose a reason for hiding this comment

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

기존 네이밍이 더 좋아보여요. 이 자체로는 특별한 기능없는 표준 Input 요소이고, Tag(도메인) 를 입력하기 위한 특별한 스타일을 가진 input 요소니까, TagInput이 더 좋아보입니다. export되고 있지않고 이 파일안에서만 사용하고, 이미 "Tag"라는 맥락이 충분히 이 파일안에서 파악가능하니까 그냥 Input이라고만 해도 무방할거같고요. (사실 그러면 공통컴포넌트같아지는 이슈가 있지만...)

width: 100%;
height: 56px;
background: #f3f4f6;
Expand Down Expand Up @@ -111,4 +126,4 @@ const CloseIcon = styled.img`
width: 20px;
height: 20px;
`;
export default InputTag;
export default TagInput;
File renamed without changes.
Loading