-
Notifications
You must be signed in to change notification settings - Fork 0
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
[4주차 기본/심화/공유 과제] API 통신 #7
base: main
Are you sure you want to change the base?
Conversation
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와 TypeScript를 활용해서 과제 잘해주신 것 같습니다!! 컴포넌트 구조와 상태 관리가 잘 되어있어 전반적으로 가독성, 유지보수성 모두 잘 고려한 코드로 과제하느라 고생하셨습니다 🫶
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.
'getMyHobby' 와 'getOtherUserHobby' 두 함수 모두 API 호출 로직이 비슷한 거 같아요! 이를 하나의 공통 유틸리티 함수로 추출하여 재사용성을 높일 수 있지 않을까,, 싶습니당
@@ -0,0 +1,140 @@ | |||
import React, { useState } from 'react'; | |||
import styled from 'styled-components'; | |||
import { AiFillEye, AiFillEyeInvisible } from 'react-icons/ai'; |
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.
AiFillEye와 AiFillEyeInvisible 아이콘을 사용해서 비밀번호 보이기/숨기기 심화 기능까지 구현하다니!! 🤩
<Routes> | ||
<Route path="hobby" element={<HobbyPage />} /> | ||
<Route path="info" element={<InfoPage />} /> | ||
<Route path="*" element={<Navigate to="hobby" replace />} /> |
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.
오옹 존재하지 않는 경로로 접근 시 hobby로 리디렉션하도록 처리한 거 맞을까요??
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.
역시 코드 뿐만 아니라 디자인 까지도 너무 예쁘네요 .. 🥹 저도 코드 뿐만 아니라 디자인 까지 혼자 잘 해낼 수 있을 때 까지 달려볼게요 ~~..!! 4주차 과제 너무 수고 많으셨고 합세도 잘 부탁드려요 🙌🖤
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 InfoPage from '../components/MyPage/Info'; | ||
|
||
const MyPageRoutes = () => { | ||
return ( |
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.
라우터 설정은 요즘 createBrowserRouter를 사용하면 코드의 확장성과 유지보수에 더 좋습니다! 왜냐하면 createBrowserRouter는 객체방식으로 라우터를 정의하여 별도 파일로 분리하거나 재사용하기 쉬운 구조를 제공하기 때문입니다.
const renderStep = () => { | ||
if (step === 1) return <NameInput onNext={nextStep} setUsername={setUsername} />; | ||
if (step === 2) return <PasswordInput onNext={nextStep} setPassword={setPassword} password={password} />; | ||
if (step === 3) return <HobbyInput onNext={handleSignUp} hobby={hobby} setHobby={setHobby} />; | ||
}; |
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.
요런 함수들을 커스텀훅으로 분리해보는건 어떨까요?
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.
로직 분리 하려고 노력하신 것도 보이고, 함수화도 잘 시키셧고, 스타일도 잘 입히신 것 같고
전반적으로 깔끔하게 잘 하신 것 같아요~
고생하셨습니다! 👍👍👍
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.
요 파일은 npm install을 했을 때 생기는 파일로 알고 있는데, 명령어를 잘못 입력하셨던걸까요 ㅠ 저희는 yarn 을 사용해서 이 파일이 아니라, yarn.lock 파일이 생겨야 하는게 맞습니다...!
아니면 혹시 yarn이 아니라 npm을 사용하고 계실까요?
<Router> | ||
<Routes> | ||
<Route path="/" element={<LoginPage />} /> | ||
<Route path="/signup" element={<SignUpPage />} /> | ||
<Route path="/mypage/*" element={<MyPage />} /> | ||
</Routes> | ||
</Router> |
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.
<BrowserRouter>
를 사용해서 라우팅을 구현해주셨네요!
그런데, 이 방식 대신 createBrowserRouter를 사용하는 것을 더 추천드리고 싶어요!
결론부터 말씀드리면, createBrowserRouter는 라우트 설정을 보다 명시적이고 구조적으로 작성할 수 있도록 도와주는 최신 API입니다.
또한, 코드가 더 직관적이고 관리하기 쉬워지는 장점이 있어요.
문제점
-
라우트 설정의 명시성 부족
<BrowserRouter>
방식은 라우트와 컴포넌트들을 JSX 안에서 설정해야 하기 때문에, 라우트 구조가 복잡해질수록 관리가 어려워질 수 있습니다. -
코드의 확장성과 유지보수
createBrowserRouter는 라우트를 객체 형태로 정의하여 별도 파일로 분리하거나 재사용하기 쉬운 구조를 제공합니다. 이런 방식은 코드 확장성과 유지보수에 유리합니다.
따라서, createBrowserRouter를 활용하면 아래와 같은 방식으로 작성할 수 있어요:
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
const router = createBrowserRouter([
{
path: '/',
element: <Home />,
children: [
{ path: 'about', element: <About /> },
{ path: 'contact', element: <Contact /> },
],
},
{
path: '/signup',
element: <SignUpPage />,
},
]);
<RouterProvider router={router} />;
위와 같은 방식은 라우트 구성과 UI 구성이 분리되기 때문에 코드의 가독성과 확장성이 더 좋아집니다!
관련 공식 문서 한 번 읽어보시는 것도 추천드려요 😊
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.
전체 페이지에 대한 라우팅은 App.tsx에서 이뤄지고 있고,
MyPage에 대한 라우팅은 /routes/MyPageRoutes.tsx에서 이뤄지고 있는데,
라우팅을 하는 로직이 여러 파일에 분산되어 있으면 유지보수가 어렵지 않을까요...?
파일 분리는 하더라도, 적어도 같은 폴더에서 하는 것이 좋다고 생각하는데, 다현님은 어떻게 생각하시나요
const HeaderContainer = styled.div` | ||
display: flex; | ||
justify-content: space-between; | ||
align-items: center; | ||
padding: 1.5rem 2rem; | ||
background-color: ${({ theme }) => theme.colors.primary}; | ||
color: ${({ theme }) => theme.colors.white}; | ||
width: 100%; | ||
`; |
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.
HeaderContainer라면 div태그보단 header태그가 더 적절할 것 같아요!
✨ 구현 기능 명세
💡 기본 과제
취미
,내 정보
메뉴 탭로그아웃
버튼취미
,내 정보
취미 페이지, 내 정보 페이지 출력 (1개의 페이지로 구현해도 되고, url 달라도 됨)🔥 심화 과제
공유과제
제목: 한 번 설정해두면 개발이 편해지는,,, Axios Interceptor
링크 첨부 : https://wave-web.tistory.com/131
❗️ 내가 새로 알게 된 점
1.
Promise<>
비동기 작업에서 Promise<>를 사용해서 반환 타입을 지정하는 방법을 알게 되었다.
🎈 Promise<>가 뭐지?
Promise<>는 비동기 작업이 완료되었을 때 결과를 반환할 것을 약속하는 객체이다. 작업이 성공하면 resolve를 통해 원하는 데이터를 반환하고 실패하면 reject로 에러를 전달한다.
Promise<>
안에 있는 꺽쇠 괄호< >
는 그 비동기 작업이 성공했을 때 반환될 데이터의 타입을 명시하는 부분이다.위 코드처럼 Promise라고 쓰면 fetchData라는 비동기 함수가 숫자 타입 데이터를 반환할 것을 보장하게 된다. await나 .then()으로 받아올 데이터가 미리 예상 가능한 타입으로 지정되니까 타입스크립트에서 오류를 줄이고 코드의 안전성을 높일 수 있는 장점이 있다!
2. axios interceptor
api에서 헤더에 토큰 넣는 코드를 반복적으로 쓰다가 이 중복 코드를 어떻게 처리하면 좋을까 하다 알게 된 기능이다. 근데 과제 마감 얼마 안 남고 알게 된 거라 적용해서 리팩토링 할 예정,,, -> 수정했음!
🎈axios interceptor가 뭐지?
3.
React.ChangeEvent<HTMLInputElement>
특정 타입의 입력 이벤트를 다룰 때 쓰면 유용한 기능이다. 특히 input 필드와 같은 HTML 요소에 사용자가 텍스트를 입력할 때 발생하는 이벤트를 다룰 때 유용하다.
아래처럼 input 필드의 값이 변할 때마다 발생하는 onChange 이벤트 핸들러를 만들었을 때
React.ChangeEvent<HTMLInputElement>
는 input 요소에서 발생하는 이벤트라고 명확하게 타입을 지정해주는 역할을 한다. 이 타입을 지정하면 event.target.value에 접근할 때 타입스크립트가 자동으로 이 값이 string 타입이라는 걸 인식하니까 추가적인 타입 체크나 변환 없이 안전하게 사용할 수 있다.4. 타입스크립트에 대한 전반적인 이해,, 기본적인 개념들,,,
5.
React.Dispatch<React.SetStateAction<string>>
이번에 상태 업데이트 함수를 다른 컴포넌트로 전달하려고 하다 보니 그 함수에 타입을 어떻게 지정할지 고민하게 되었다... 상태를 설정하는 함수인데 단순히 string 타입으로만 지정하면 안 됐었다.
그래서 찾아보니까 React의 Dispatch와 SetStateAction 타입이 있다는 걸 알게 되었다.
React.Dispatch<React.SetStateAction<string>>
로 지정하면 문자열 상태를 업데이트하는 함수라는 의미를 전달할 수 있었고 덕분에 이 함수를 받는 컴포넌트에서도 상태 설정 함수라는 걸 명확히 알 수 있게 되어 타입 안전성도 확보됐다!이 타입은 기본적인 setState 함수 타입을 React에서 직접 제공해 주기 때문에 굉장히 유용하다! 이걸 쓰면 상태를 업데이트하는 함수 타입을 간단히 선언할 수 있다. 이제 상태를 업데이트하는 함수가 필요할 때마다 이 친구를 써주면 훨씬 수월해질 듯,, 👍🏻
❓ 구현 과정에서의 어려웠던/고민했던 부분
1. 타스 초기 세팅
처음에 vite로 타입스크립트를 설정하고 나니,,, 진심 config 파일이나 App.tsx에서 에러가 엄청 많이 떴다. 근데 아무리 찾아봐도 해결이 안 되길래 (에러 하나 해결하면 다른 데서 에러 10개 남) 시작 전부터 살짝 포기할 뻔 했다... ㅎㅎ 근데 다행히 https://velog.io/@otterji/Vite-tsconfig-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0 이런 글을 본 후에 vscode를 업데이트 해봤더니 에러가 안 났다! 물론 vscode 업데이트 하는 법도 헤매서 오래 걸리긴 했지만 이런 원인일 거라고는 상상도 못했다.
2. 내 취미 조회 useEffect 안 쓰고 어떤 방법으로 구현해야할까?
useEffect를 쓰지 않는 게 맞다고 해서 내 취미 조회할 때 useEffect를 쓰지 않으려고 했는데 그럼 어떤 방식으로 대체해서 구현해야할지 감이 안 와요.. 다들 이 부분에 대해 어떻게 구현하셨는지 궁금해요
3. 폴더 구조 및 컴포넌트 분리
이건 과제할 때마다 어떻게 컴포넌트나 훅들을 분리해야 할지 폴더 구조는 어떻게 하는 게 맞는 건지에 대해 오래 고민하게 되다보니 항상 궁금해지는 부분인 것 같습니다... 단일 책임 원칙에 최대한 따르려고 노력했는데 아직 부족한 거 같아요 ㅜㅜ 다들 어떻게 하셨는지 궁금합니다! 공통 컴포넌트를 잘 분리 못한 거 같기도 하고,, 유효성 검사 로직 같은 걸 유틸로 분리하는 게 좋을지 고민이네용
🥲 소요 시간
18h
🖼️ 구현 결과물
회원가입
default.mov
로그인
default.mov
취미
default.mov
내 정보
default.mov
로그아웃
default.mov