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

[4주차 기본/심화/공유 과제] 회원가입 & 로그인 #5

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

hansoojeongsj
Copy link
Contributor

@hansoojeongsj hansoojeongsj commented Nov 12, 2024

✨ 구현 기능 명세

💡 기본 과제

  • React + TypeScript
  • Axios 라이브러리 사용
  • ThemeProvider, GlobalStyle 사용
  1. 로그인
  • 로그인 타이틀
  • 아이디(이름) 입력 Input
  • 비밀번호 입력 Input
  • 로그인 버튼 (hover시 배경색 바꾸기 (transition 적용))
  • 회원가입 버튼 (회원가입 페이지로 이동)
  1. 회원가입
  • 이름 - 비밀번호 - 취미 입력이 한 페이지에서 일어남 (컴포넌트만 갈아끼우기)
  • 상단에 회원가입 타이틀
  • 하단에는 로그인 페이지로 가는 링크
  1. 회원가입(이름)
  • 이름 입력 Input
  • 다음 버튼 (비밀번호 입력 폼 나옴)
  • Input 비어있을 때 버튼 비활성화
  1. 회원가입(비밀번호)
  • 비밀번호 입력 Input
  • 비밀번호 확인 Input
  • 둘 중 하나라도 비어있으면 버튼 비활성화
  • 두 비밀번호가 다르면 버튼 비활성화
  • 다음 버튼 (취미 입력 폼 나옴)
  1. 회원가입(취미)
  • 취미 입력 Input
  • 회원가입 버튼
  • Input 비어있을 때 버튼 비활성화
  • 회원가입 실패 시 에러메시지 alert 출력
  • 회원가입 성공 시 회원번호 alert 출력하고, login 페이지로 이동
  1. 마이페이지
  • 헤더에 취미, 내 정보 메뉴 탭
  • 헤더에 로그아웃 버튼
  • 로그아웃 버튼 클릭 시 token 저장 정보 삭제하고 로그인 페이지로 이동 (token 저장 위치는 자율)
  • 헤더 취미, 내 정보 취미 페이지, 내 정보 페이지 출력 (1개의 페이지로 구현해도 되고, url 달라도 됨)
  1. 마이페이지(취미)
  • 나의 취미 출력
  • 사용자 번호 입력 Input
  • 검색 버튼
  • 검색 오류시 alert
  • 검색된 취미 출력
  1. 마이페이지(내 정보)
  • 비밀번호만 입력하면 비밀번호만 변경
  • 취미만 입력하면 취미만 변경
  • 둘 다 입력하면 둘다 변경
  • 둘 다 비어있으면 alert

🔥 심화 과제

  • any 사용하지 않기
  1. 회원가입 (이름)
  • 8글자 넘어가도 버튼 비활성화 처리
  • 8글자 넘어가는 것에 대해 에러메시지 출력
  1. 회원가입 (비밀번호)
  • 비밀번호 보이기 버튼 추가
  • 8글자 넘어가도 버튼 비활성화 처리
  • 8글자 넘어가는 것에 대해 에러메시지 출력
  • 비밀번호 불일치 에러 메시지 출력
  • (선택) 에러메시지 한개만 출력해도 됨 (우선순위는 알아서)
  1. 회원가입 (취미)
  • 8글자 넘어가도 버튼 비활성화 처리
  • 8글자 넘어가는 것에 대해 에러메시지 출력

공유과제

제목: 타입스크립트의 타입

링크 첨부 : https://wave-web.tistory.com/122


❗️ 내가 새로 알게 된 점

  • interface를 사용하여 객체나 함수의 타입을 명확하게 정의하는 방법을 알게 되었습니다. 예를 들어, LoginProps에서 onLogin 함수가 LoginData 타입을 인자로 받도록 정의할 수 있다는 점이 유용하게 느껴졌습니다.
  • useState로 상태에 타입을 지정하는 방법을 배웠습니다. 이 방식은 상태의 타입을 명확하게 정의할 수 있어서, 타입스크립트가 상태 값을 자동으로 추론하게 도와주었니다. 예를 들어, loginData 객체가 반드시 username과 password라는 두 속성을 가진다는 것을 보장할 수 있었습니.
  • useNavigate 훅을 사용하여 페이지 이동을 구현하는 방법을 알게 되었습니다. 이를 통해 사용자가 버튼 클릭 시 다른 페이지로 이동하도록 할 수 있었습니다. 예를 들어, navigate('/signup')으로 회원가입 페이지로 이동하는 기능을 쉽게 구현할 수 있었습니다.
  • 로 입력 요소의 타입을 지정하는 방법을 알게 되었습니다. React.ChangeEvent를 사용하여 요소에서 발생하는 이벤트를 정확히 처리하고, 입력 값에 안전하게 접근할 수 있다는 점이 신기했습니다.
  • props를 통해 함수를 전달할 때 interface로 그 타입을 정의하는 방법을 알게 되었습니다. 코드에서, onLogin 함수처럼 부모 컴포넌트에서 자식 컴포넌트로 함수를 전달할 때, 그 타입을 interface로 명확히 정의함으로써 함수 호출 시 예상되는 매개변수와 반환 타입을 보장할 수 있는 것이 신기했습니다.

❓ 구현 과정에서의 어려웠던/고민했던 부분

  • 콘솔에 경고 메시지가 없어지지 않아요.. React Router v6에서 v7로 업그레이드 관련 경고 메시지라고 하던데 다들 이 메시지가 있는지 궁금합니다.
  • 타입스크립트가 전체적으로 다 낯선데, 이렇게 하는 게 맞는지 궁금합니다..ㅎ
  • 서버의 상태코드와 에러코드가 많아 에러 메시지를 다 띄워주려고 노력은 했는데, 이렇게 하는 게 맞는지 궁금합니다.
  • axios를 각각 파일에서 해주었는데 apis폴더를 만들고 axiosInstance 같은 파일을 만들고 빼주는 게 더 좋겠죠..? 노력해보겠습니다..
  • ㅎ ㅏ...

🥲 소요 시간

  • 20h

🖼️ 구현 결과물

회원가입(이름)

-.Chrome.2024-11-12.15-18-48.mp4

회원가입(비밀번호, 취미)

-.Chrome.2024-11-12.15-19-53.mp4

로그인, 로그아웃

-.Chrome.2024-11-12.15-21-27.mp4

마이페이지(취미)

-.Chrome.2024-11-12.15-22-14.mp4

마이페이지(내 정보)

-.Chrome.2024-11-12.15-22-24.mp4

@hansoojeongsj hansoojeongsj changed the title "[4주차 기본/심화/공유 과제] 회원가입 & 로그인 [4주차 기본/심화/공유 과제] 회원가입 & 로그인 Nov 13, 2024
Copy link
Member

@gudusol gudusol left a comment

Choose a reason for hiding this comment

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

코드도 깔끔하게 짜시고,
로직분리도 잘하신 것 같아요 ~!

고생하셨습니다 👍👍👍

@@ -0,0 +1,10 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
Copy link
Member

Choose a reason for hiding this comment

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

App.css, index.css 파일은 빈 파일이므로 삭제해줘도 괜찮을 것 같습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

넵 바로 삭제 했습니다..!

Comment on lines 19 to 29
margin: 3rem;
color: ${({ theme }) => theme.colors.black};
`;

export const InputWrapper = styled.div`
margin-bottom: 15px;
width: 100%;
`;

export const Input = styled.input`
padding: 10px;
Copy link
Member

Choose a reason for hiding this comment

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

margin에는 rem, padding에는 px 등으로 단위를 섞어서 사용하시고 있는 것 같은데,
혹시 단위를 사용하신 기준이 있으실까요?

그게 아니라면 단위를 일관성이 있게 사용하시는것이 유지보수나 가독성 측면에서 더 좋을 것 같습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

이유 없습니다.... 바봅니다. 수정하겠습니다.

Comment on lines 6 to 8
import Login from './pages/LoginPage';
import Signup from './pages/SignupPage';
import MyPage from './pages/MypagePage';
Copy link
Member

Choose a reason for hiding this comment

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

다른 이름으로 받아오는 것도 좋지만 파일명과 같은 이름으로 import해오는 것은 어떨까요?

특히 이 프로젝트같이, LoginPage와 Login 컴포넌트가 둘다 있는 경우에는, 헷갈릴 우려가 있을 것 같습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

아.. 놓친 부분이 너무 많네요. 수정하겠습니다.

Comment on lines 63 to 65
<div>
<Login onLogin={handleLogin} />
</div>
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
<div>
<Login onLogin={handleLogin} />
</div>
<Login onLogin={handleLogin} />

요기도 div가 없어도 될 것? 같습니다..!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

넵 수정했습니다

Comment on lines 10 to 13
const [username, setUsername] = useState<string>('');
const [password, setPassword] = useState<string>('');
const [hobby, setHobby] = useState<string>('');
const [step, setStep] = useState<number>(1);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
const [username, setUsername] = useState<string>('');
const [password, setPassword] = useState<string>('');
const [hobby, setHobby] = useState<string>('');
const [step, setStep] = useState<number>(1);
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [hobby, setHobby] = useState('');
const [step, setStep] = useState(1);

이렇게 초기값을 지정해준 경우, type을 명시적으로 알려주지 않고, typescript가 자동으로 추론하게 하는 것이 좀 더 권장되는 방식이라고 합니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

오호.... 처음 알았습니다 !! 앞으로 이 점 생각해서 코드 작성하겠습니다! 감사합니다.

Comment on lines 35 to 38
<>
<Label htmlFor="hobby">취미</Label>
<InputWrapper>
<Input
Copy link
Member

Choose a reason for hiding this comment

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

몬가 정렬이 이상한 것 같아요..!
prettier 설정을 확인해보면 좋을 것 같습니다! 모르겠으면 절 호출해주세요~

Copy link
Contributor Author

Choose a reason for hiding this comment

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

prettier 설정 했습니다. 감사합니다!

Comment on lines 14 to 20
export const Title = styled.p`
font-size: 2.5rem;
text-align: center;
flex: 1;
margin-right: 2rem;
`;

Copy link
Member

Choose a reason for hiding this comment

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

Title이면 p태그 보다는 h1 ~ h6등 헤딩 태그가 더 적적할것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

꼼꼼하십니다. 바로 수정했습니다!

Comment on lines 30 to 31
const response: AxiosResponse<MyHobbyResponse> = await axios.get(
'http://211.188.53.75:8080/user/my-hobby',
Copy link
Member

Choose a reason for hiding this comment

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

api 요청마다 baseUrl을 작성하는 등 과정을 줄이기 위해 axios instance를 만들어서 해보시는 것도 좋을 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

넵 도전해보겠습니다

import MypageInfo from '../components/Mypage/MypageInfo';

const MypagePage = () => {
const [selectedComponent, setSelectedComponent] = useState<string>('취미');
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
const [selectedComponent, setSelectedComponent] = useState<string>('취미');
const [selectedComponent, setSelectedComponent] = useState<'취미' | '내 정보'>('취미');

이와 같은 선택 메뉴 처럼 특정 값만 오는 state의 경우에는
string타입 보다는 올 수 있는 값들만 명시해주면 조금 더 안전한 코드를 작성할 수 있을 것 같습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

오.. 👍👍 올 수 있는 값만 명시하면 더 안전한 코드가 되는군요..! 수정했습니다!

@hansoojeongsj hansoojeongsj self-assigned this Dec 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants