-
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주차 기본, 심화]🍁 로그인/회원가입🍁 #11
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.
심화과제까지 넘넘 잘해줬네요 !!!
axios, async-await, api 통신, 라우터 ... 등등 이번 과제의 핵심들을 너무너무 잘 적용해주고있어서 잘한다잘한다 !! 하면서 코드리뷰 달았답니당 !
이제 state로 전달하고 렌더링을 어떻게 해야하는지는 익숙해진 것 같으니 ! 어떻게하면 컴포넌트의 재사용성을 올릴 수 있을지, 페이지별로 중복되는 컴포넌트는 무엇인지 (공통 wrapper로 사용할 수 있는 레이아웃은 어떤게 있을지!)를 고민하면서 view구조를 짜고,
내가 이 데이터값(state값)을 어느어느 컴포넌트에서 사용해야하는지, 그렇다면 그 컴포넌트들의 공통 부모가 어디인지 ! 등을 고려해서 state을 정의할 위치, 정의할 방법 (useState, useReducer, 더 나아가면 context API까지!) 를 고민해보면서 디벨롭해가면 정말정말 좋을 것 같아요 !!
디자인도 넘넘 깔꼼하구 ... 잘했다잘했다 ! 수고했어요오 ! 💗💗💗
headers: { | ||
"Content-Type": "application/json", | ||
}, |
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.
header까지 넣어서 만들었구나 ! 굿굿!
이번 과제에서는 header를 바꿀일이 없으니 이렇게 만들어서 export하는 것 좋네용 !
const Cta = { Main, Secondary }; | ||
export default Cta; |
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.
상수를 export할 때는 대문자로 해줍시당 !
const CTA = { Main, Secondary };
export default CTA;
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.
밑에 보다가 첨언하러 다시 올라왔어요 ! 코드 다시 보니깐 스타일에서 로그인인지 회원가입인지에 따라서 스타일링을 다르게 해주려고 서로 다른 버튼 컴포넌트를 만든 거였더라구요 !
styled-component에서도 동적 스타일링을 할 수 있답니다 ? prop을 전달해주어서 prop값에 따른 조건부 스타일링을 할 수 있어요 !
예를들면
// login.jsx
// 로그인 버튼일 경우
<Main $login={true} >로그인</Main>
// 회원가입 버튼일 경우
<Main $login={false} >로그인</Main>
// �cta.jsx
const Main = styeld.div`
...
font-color: ${({ $login, theme }) => ($login ? theme.yellow : theme.gray2)};
`
이렇게 조건부 스타일링을 한다면 중복되는 코드를 줄이고, 하나의 버튼 컴포넌트로 렌더링할 수 있겠죠?
+) 변수 이름은 그 의미를 담고 있으면 좋아요 ! Main, Secondary보다는 LoginBtn, SignupBtn으로 짓는게 더 가독성 있겠죠 ? 💫
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.
맞아요! css 에서는 저렇게 변경되는 state의 값에 따라 동적으로 조건부 렌더링을 해주기 위해 styled components 부분에 삼항 조건 연산자를 사용하는 경우도 꽤 자주 있답니다!!
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 styled from "styled-components"; | ||
import React from "react"; | ||
|
||
const LoginForm = ({ idValue, setIdValue, pwValue, setPwValue }) => { |
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.
파일명이랑 컴포넌트 명을 맞추어주면 좋아요 !
지금 보면 inputForm 파일 안에 로그인 컴포넌트랑 회원가입 컴포넌트가 들어있는데, 하나의 파일에는 하나의 컴포넌트만 넣어두는게 좋답니다 !
그 말은 즉 로그인과 회원가입을 각자 다른 파일으로 분리하여 작성할 수 있다는 거겠죠 ?
로그인과 회원가입에서 각자 전달받는 prop도 다르기 때문에 분리하여 작성하면 가독성이 더 좋아질 거에요 ! 그리고 전달하는 prop들도 분리되어 데이터 전달 흐름도 개선할 수 있을 거에요 ! ㅎㅎ
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.
헤헤 요거 나도 리뷰 받았던 거 ! 그리구 파일명이랑 컴포넌트명을 동일하게 맞춰줌으로써 rsc
단축키로 쉽게 코드 생성이 가능하다고 함니다 - ?!
placeholder="아이디를 입력하세요" | ||
value={username} | ||
onChange={(e) => setUsername(e.target.value)} | ||
></ShortTextholder>{" "} |
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.
저 공백이, vscode에서 태그들 내부에 실수로 공백이 포함된 채로 구현하게 되면, 자동 줄 맞춤이 될 때 저렇게 {" "}
이렇게 맞춰지더라고요?! 만약 저런게 추가될 경우 발견하는 족족 지워주면 좋을 것 같습니다!!!
import React from "react"; | ||
import ReactDOM from "react-dom/client"; | ||
import App from "./App.jsx"; | ||
import GlobalStyle from "./styles/globalStyle.js"; | ||
import { ThemeProvider } from "styled-components"; | ||
import theme from "./styles/theme.js"; |
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 순서를 맞춰주면 나중에 보기에 더 편하답니다 💡
민서 다른 파일들에서는 순서 너무너무 깔꼼하게 잘 맞추어주었는데 여기에는 안 되어있어서 살짝 언급하고 지나갑니다아 ~ ㅎㅎ
const activateBtn = async () => { | ||
if ( | ||
isClicked && | ||
username && | ||
nickname && | ||
password && | ||
passwordCheck && | ||
password === passwordCheck | ||
) { | ||
await doubleCheck(); | ||
setSignupButton(true); | ||
return true; | ||
} else { | ||
setSignupButton(false); | ||
return false; | ||
} | ||
}; |
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.
async - await 적용 너무너무 잘했네요 !
try { | ||
await postData(); | ||
goToLogin(); | ||
alert("회원가입 완료"); |
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.
헉 alert까지 야무져라
nickname: nickname, | ||
password: password, | ||
}); | ||
console.log(response); |
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.
확인용 콘솔은 지워주기!
// | ||
useEffect(() => { | ||
activateBtn(); | ||
}, [isClicked, username, nickname, password, passwordCheck]); |
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.
deps값 잘 넘겨주었네용!
const getLoginData = async () => { | ||
try { | ||
const response = await apiClient.get(`/api/v1/members/${userId}`, {}); | ||
setUsername(response.data.username); | ||
setNickname(response.data.nickname); | ||
} catch (err) { | ||
console.log(err); | ||
} | ||
}; | ||
|
||
getLoginData(); |
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.
라우팅과 api 통신 모두 새로운 개념이라 적용해보기 쉽지 않았을텐데 너무너무 수고 많았습니다!!! 👍 💯 ❤️
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 프로젝트를 생성할 때마다 초기세팅의 일부로 이렇게 안쓰는 파일들은 지워주는걸 습관화하장!!
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.
보통 theme 파일에서는 color 뿐만아니라 font 등도 지정해주곤 하는데, 그래서 여러종류의 값을 사전 설정 해주기 위해 각 분류 별 객체를 colors, fonts 등으로 이름붙여서 생성해줍니다!
따라서 theme에서 만들어준 친구를 불러와서 사용할 때도
background-color: ${({ theme }) => theme.gray1};
이렇게보다
background-color: ${({ theme }) => theme.colors.gray1};
이렇게 한뎁스 더 거쳐서 접근하는 것이 일반적인 방식이랍니당
참고참고!!!
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.
문법이니까 꼭 지키기!
const Cta = { Main, Secondary }; | ||
export default Cta; |
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.
맞아요! css 에서는 저렇게 변경되는 state의 값에 따라 동적으로 조건부 렌더링을 해주기 위해 styled components 부분에 삼항 조건 연산자를 사용하는 경우도 꽤 자주 있답니다!!
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를 먼저 받아서 거치지 않고, 곧바로 곧바로 구조분해하는 방식 너무 좋아요! 👍 💯
<Wrapper> | ||
<Name>ID</Name> | ||
<Textholder | ||
type="text" | ||
placeholder="아이디를 입력하세요" | ||
value={idValue} | ||
onChange={(e) => setIdValue(e.target.value)} | ||
></Textholder> | ||
</Wrapper> |
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.
이부분도 반복되는 걸 보니 내부 텍스트 따로 배열로 관리하고 전체적인 html 구조는 공통 컴포넌트로 분리하여 재사용하기 딱 좋아보이네요!! 🥺😎
placeholder="아이디를 입력하세요" | ||
value={username} | ||
onChange={(e) => setUsername(e.target.value)} | ||
></ShortTextholder>{" "} |
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.
저 공백이, vscode에서 태그들 내부에 실수로 공백이 포함된 채로 구현하게 되면, 자동 줄 맞춤이 될 때 저렇게 {" "}
이렇게 맞춰지더라고요?! 만약 저런게 추가될 경우 발견하는 족족 지워주면 좋을 것 같습니다!!!
//id 비밀번호 | ||
const handleLogin = async () => { | ||
try { | ||
const response = await apiClient.post(`/api/v1/members/sign-in`, { | ||
username: idValue, | ||
password: pwValue, | ||
}); | ||
console.log(response.data.id); | ||
navigate(`/mypage/${response.data.id}`); | ||
} catch (err) { | ||
if (err.response && err.response.data) { | ||
setToastMessage(err.response.data.message); | ||
} else { | ||
setToastMessage("사용자를 찾을 수 없습니다"); | ||
} | ||
setShowToast(true); | ||
} | ||
}; |
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 통신 코드 너무 잘 구현해줬는데요!!
이제 여기서 한발짝 더 고려하면 좋을 부분은 바로 컴포넌트 및 파일 분리입니다!
하나의 파일, 하나의 모듈이 최대한 '한가지 일만 할 수 있도록' 컴포넌트를 분리해주면 좋은데용,
따라서 보통 UI를 렌더링하는 코드와 api통신을 하는 코드는 전혀 다른 역할을 하는 친구들이기 때문에 다른 파일로 관리하곤 한답니다!
해당 피드백 참고하여 api 통신과 관련된 코드는 별도의 파일로 분리하여 관리해주는 리팩토링 경험을 해보면 좋을 것 같아요 ❤️
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.
문법이니까 꼭 지키기!
username: idValue, | ||
password: pwValue, |
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.
애초에 state를 각각
const [userName, setUserName] = useState("");
const [password, setPassWord] = useState("");
이렇게 하면
username: idValue, | |
password: pwValue, | |
username, | |
password, |
단축 프로퍼티라는 것에 의해 이렇게도 가능하답니당? 그냥 참고!!
const response = await apiClient.post("/api/v1/members", { | ||
username: username, | ||
nickname: nickname, | ||
password: password, | ||
}); |
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 response = await apiClient.post("/api/v1/members", { | |
username: username, | |
nickname: nickname, | |
password: password, | |
}); | |
const response = await apiClient.post("/api/v1/members", { | |
username, | |
nickname, | |
password, | |
}); |
오오 여기서 이렇게 쓸 수 있겠다 ㅎㅎ
const [username, setUsername] = useState(""); | ||
const [nickname, setNickname] = useState(""); | ||
const [password, setPassword] = useState(""); | ||
const [passwordCheck, setPasswordCheck] = useState(""); | ||
const [isExist, setIsExist] = useState(""); |
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.
state 선언이 너무 많고, 밑에 props로 넘겨줄 친구가 너무 많아진 문제를 동시에 해결할 수 있는 방법으로
const [username, setUsername] = useState(""); | |
const [nickname, setNickname] = useState(""); | |
const [password, setPassword] = useState(""); | |
const [passwordCheck, setPasswordCheck] = useState(""); | |
const [isExist, setIsExist] = useState(""); | |
const initInputInfo = { | |
username: "", | |
nickname: "", | |
password: "", | |
passwordCheck: "", | |
isExist: "", | |
} | |
const [inputInfo, setInputInfo] = useState(initInputinfo); |
이런식으로 객체 하나로 state를 관리할 수 있다는거! 그럼 각각이 변경되었을 때의 로직도 하나로 묶을 수 있게된답니당
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.
민서가 ✨우수잔디✨상을 타서 과제를 구경하러 왔어요💛 정말 같이 왕초보에서 시작했는데 민서 어디까지 성장하는 건가요 ? ? ? 정말 저만 잘하면 되겠어요,,~ 컴포넌트 분리해준 것도 그렇고 axios create 사용해서 API 붙인 것도 다 넘넘 대단해요 👍 정말 보고 배워야겠어요 ! 성장하는 민서 너무 멋져요 ! !! 💛
지금 봤는데 이 금잔디조에서 우수 과제를 2명이나 탄 거냐며ㅜ 여기 갓잔디조였네,,
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
|
||
<style> | ||
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+KR:wght@100;200;300;400;500;600;700&family=Noto+Sans+KR:wght@100;200;300;400;500;600;700;800;900&display=swap"); |
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는 성능 문제가 있을 수 있다고 하더라구요 ?
https://webclub.tistory.com/127
ㄴ 위에는 관련 링크입니다 !
합세 때도 글로벌 스타일 안에 @import를 하니까 warning이 났어서 저는 link
태그를 이용했던 기억이,, 민서도 참고하면 좋을 것 같아요 ! !!
import styled from "styled-components"; | ||
import React from "react"; | ||
|
||
const LoginForm = ({ idValue, setIdValue, pwValue, setPwValue }) => { |
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.
헤헤 요거 나도 리뷰 받았던 거 ! 그리구 파일명이랑 컴포넌트명을 동일하게 맞춰줌으로써 rsc
단축키로 쉽게 코드 생성이 가능하다고 함니다 - ?!
background-color: ${({ theme }) => theme.gray1}; | ||
width: 100%; | ||
margin: 0 auto; | ||
font-family: 'Noto Sans KR', sans-serif; |
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.
완전완전완전 사소한 거지만 여기 들여쓰기두 맞춰주면 좋을 듯 해요 !!!
@@ -0,0 +1,12 @@ | |||
const theme = { |
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 activateBtn = async () => { |
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 가져다 붙일 때만 async - await 쓸 줄 아는데,, 어떻게 이런 생각까지,, 야무져요오,,, 👍👍👍👍👍👍
✨ 구현 기능 명세
🌱 기본 조건
.env
파일 사용하기🧩 기본 과제
[ 로그인 페이지 ]
/mypage/:userId
로 넘어갑니다.(여기서
userId
는 로그인 성공시 반환 받은 사용자의 id)/signup
으로 이동합니다.[ 회원가입 페이지 ]
중복체크 버튼
회원가입 버튼
/login
으로 이동합니다.[ 마이 페이지 ]
/mypage/:userId
의 userId를 이용해 회원 정보를 조회합니다.🌠 심화 과제
[ 로그인 페이지 ]
createPortal
을 이용합니다.[ 회원가입 페이지 ]
비밀번호 확인
중복체크
생각과제
💎 PR Point
파일구조
point 1) 로그인 시 해당 페이지로 이동
${response.data.id}
상대경로로 이동로 usenavigate 사용해서 이동point 2) 회원가입 버튼 활성화/비활성화
1. 조건문
username
password
nickname
passwordCheck
password=== passwordCheck
조건문await
으로 doubleCheck가 실행되었을 때 아래 버튼이 활성화 될 수 있게 설정2. 실시간으로 상태 업로드
isClicked
(선택되었을 때 파란색 또는 빨간색 뜨게 하는 버튼)username
password
passwordCheck
각각 모두 변화가 일어날 때useEffect
로 activateBtn를 실행point 3) 마이페이지 조회
useParams
사용해서 해당 userID값 페이지로 이동point 4) toast 구현 및 message 동적 생성
onClose
될 수 있게 useEffect 사용해서 구현하고, login 페이지 최하단에서 불러오기point 5) 중복확인 체크해제
isChecked
선택시 red, blue 중 선택, 그 외에isChecked
false일때는 gray2ActiveBtn
에 넣어서 버튼 색 나오게🥺 소요 시간, 어려웠던 점
3일
state
가 여러개 추가되면서 조금 헷갈려서 오래걸렸어요!🌈 구현 결과물
2023-11-17.9.16.19.mov
2023-11-17.9.16.42.mov
2023-11-17.9.17.31.mov
2023-11-17.9.18.08.mov