-
Notifications
You must be signed in to change notification settings - Fork 26
[정상인] sprint4 #90
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
[정상인] sprint4 #90
The head ref may contain hidden characters: "Basic-\uC815\uC0C1\uC778-sprint4"
Conversation
|
스프리트 미션 하시느라 수고 많으셨어요. |
|
크으 ~ 커밋 정말 깔-끔하네요 👍 |
중복되는 코드가 많아서 리팩토링을 계속 시도하는 중이지만 아직 실패입니다 ㅠㅠ.오오 굿굿. 리팩토링을 고려하시는 것 자체가 긍정신호입니다 👍 |
버튼 활성화에 대해서 "focusout" 이 아닌 "input" 이벤트를 사용하면 좀 간단해질 것 같은데 input이벤트를 사용해도 되나요?"사용자 경험" 측면에서 "더욱 간단해진다"라는 의미라면 강사가 아닌 유저로서 공감이 됩니다. 😉
|
| <div class="landing-area"> | ||
| <div class="landing-area-left"> | ||
| <h2 class="description"> | ||
| <h1 class="description"> |
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.
<h1> 태그는 문서에 하나만 넣는게 어떨까요?
이하 MDN 발췌
페이지 당 하나의 <h1>만 사용하세요. 여러 개를 써도 오류는 나지 않겠지만, 단일 <h1>이 모범 사례로 꼽힙니다. 논리적으로 생각했을 때도, <h1>은 가장 중요한 제목이므로 전체 페이지의 목적을 설명해야 할 것입니다. 두 개의 제목을 가진 책이나, 여러 개의 이름을 가진 영화는 볼 수 없죠! 또한 스크린 리더 사용자와 SEO에도 더 적합합니다.
| @@ -1,4 +1,4 @@ | |||
| .login-btn { | |||
| .go-login-btn { | |||
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.
(심화/생각해보기/제안) login은 '기능'을 의미해요. 스타일 이름은 "어떤 스타일인지"를 목표로 네이밍을 작성해보면 어떨까요?
| .go-login-btn { | |
| <a href="/login.html" class="button button-primary">로그인 </a> |
만약, 현재 button-login과 같은 스타일의 "장바구니에 담기" 라는 버튼이 존재한다면 클래스 이름이 어떻게 될까요?
button-login 클래스로 작성한다면 login이라는 "기능"을 목적으로 하는 클래스 이름을 넣게 될거예요. 혹은 중복된 스타일과 다른 클래스 이름인 button-add-wish와 같은 클래스 이름을 가지게 돼요. 이는 재사용성을 저하시킬거예요.
차라리 해당 클래스가 "어떤 스타일을 포함하는가?"에 목적을 두어 네이밍을 한다면 더욱 재사용하기 용이할거라고 생각해서 제안드립니다 😊
priamry: 주로 브랜드의 주요 컬러를 의미합니다 ! 😊 판다마켓의 경우 파란색이죠 !
| export const clearErrorTag = (element) => { | ||
| const errorTag = element.nextElementSibling; | ||
| if (errorTag && errorTag.classList.contains("error-message")) { | ||
| element.classList.remove("error-status"); | ||
| errorTag.remove(); | ||
| } | ||
| }; | ||
|
|
||
| export const createErrorTag = (element, message) => { | ||
| const tag = document.createElement("p"); | ||
| tag.classList.add(`error-message`); | ||
| tag.textContent = message; | ||
| element.classList.add("error-status"); | ||
| return element.after(tag); | ||
| }; | ||
|
|
||
| export const isValidEmail = (email) => { | ||
| const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; | ||
| return emailRegex.test(email); | ||
| }; |
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.
크으 ~ 함수들이 하나같이 외부 환경에 영향을 주지 않는군요 !
'인자로 받은 것들만을 처리' 하며, 외부에 무언가 영향을 주는 함수가 없네요 👍
상인님께서 작성하신 이러한 함수를 “순수 함수(Pure Function)” 라고 부릅니다.
이러한 구조는 테스트하기도 쉽고, 예측 가능한 코드 작성에 도움이 되는 좋은 패턴입니다.
지금처럼 유틸리티 함수를 순수하게 분리해 작성하는 습관, 정말 잘 하고 계세요! 🔥
| @@ -0,0 +1,33 @@ | |||
| export const isValidValue = { | |||
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.
(권장) is~는 통상적으로 boolean 변수명을 작성할 때 쓰입니다 !
| export const isValidValue = { | |
| export const formValidState = { |
하지만 값은 객체로 작성되어있군요 !
| export const isValidValue = { | ||
| login: { | ||
| loginEmail: false, | ||
| loginPassword: false, | ||
| }, | ||
| signup: { | ||
| signupEmail: false, | ||
| signupNickname: false, | ||
| signupPassword: false, | ||
| signupCheckPassword: 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.
(심화/생각해보기) 구조가 정말 좋아요. 스키마로 거듭날 수도 있겠군요 !
문제 해결 방법에 대한 접근이 정말 좋아요 !
다음과 같이 스키마 형태로 발전시킬 수도 있겠네요 !:
| export const isValidValue = { | |
| login: { | |
| loginEmail: false, | |
| loginPassword: false, | |
| }, | |
| signup: { | |
| signupEmail: false, | |
| signupNickname: false, | |
| signupPassword: false, | |
| signupCheckPassword: false, | |
| }, | |
| }; | |
| export const signupSchema = { | |
| email: { | |
| isValid: false, | |
| validate: (value) => /\S+@\S+\.\S+/.test(value), | |
| message: { | |
| void: "이메일을 입력해주세요.", | |
| invalid: "잘못된 이메일 형식입니다.", | |
| }, | |
| }, | |
| nickname: { | |
| isValid: false, | |
| validate: (value) => value.trim().length > 0, | |
| message: { | |
| void: "닉네임을 입력해주세요.", | |
| }, | |
| }, | |
| password: { | |
| isValid: false, | |
| validate: (value) => value.length >= 8, | |
| message: { | |
| void: "비밀번호를 입력해주세요.", | |
| invalid: "8자 이상 입력해주세요.", | |
| }, | |
| }, | |
| checkPassword: { | |
| isValid: false, | |
| validate: (value, original) => value === original, | |
| message: { | |
| invalid: "비밀번호가 일치하지 않습니다.", | |
| }, | |
| }, | |
| }; |
상인님께서는 제가 알기로 리액트도 어느 정도 해보셨다고 알고 있어서 조금은 심화된 피드백을 드려봅니다. 😉
나중에는 zod나 joi같은 유효성 검사 라이브러리도 사용해보실 수도 있습니다 ! 😊
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.
재사용성을 고려하신 설계가 정~말 좋습니다 👍
| </button> | ||
| </div> | ||
| <button class="form-submit-btn disabled" disabled>로그인</button> | ||
| <button type="submit" class="button form-btn" id="login-btn" disabled> |
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.
굿굿 ~! type까지 명시해두셨군요 ! 👍
button의 type은 submit으로 기본값이긴 하나, 의도가 명확하네요 ~!
| if (!value) { | ||
| const errorTag = createErrorTag(e.target, "비밀번호를 입력해주세요"); | ||
| $loginBtn.disabled = true; | ||
| return errorTag; | ||
| } | ||
|
|
||
| if (value.length < 8) { | ||
| const errorTag = createErrorTag( | ||
| e.target, | ||
| "비밀번호를 8자 이상 입력해주세요." | ||
| ); | ||
| $loginBtn.disabled = true; | ||
| return errorTag; | ||
| } |
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.
굿굿 ! Guard Clause 패턴으로 가독성을 향상시켰군요 ! 👍👍
Guard Clause 패턴을 사용하고 계시군요 ! 멋집니다 상인님.
조건부를 조기에 처리할 수 있게 되어 핵심 로직을 구분할 수 있다는 장점이 있습니다. 따라서 가독성을 향상시킬 수 있어요.
또한, 미리 조건에 따라서 데이터의 범위를 좁힐 수 있기에 핵심 로직에서는 보장받은 데이터를 편리하게 사용할 수 있다는 장점도 있어요 😊
Guard Clause ?
다음과 같이 조기에 함수를 끝내는 기법을 의미합니다:
function calculateDiscount(price, discountRate) {
// Guard Clause: 가격이나 할인율이 유효하지 않으면 함수 종료
if (price <= 0 || discountRate <= 0 || discountRate > 1) {
console.error("Invalid price or discount rate");
return;
}
// 할인된 가격 계산
const discountedPrice = price * (1 - discountRate);
return discountedPrice;
}|
수고하셨습니다 상인님~!! 유효성 검증 로직의 정리와 재사용성도 인상 깊었습니다. 앞으로도 지금처럼 탄탄한 설계와 세심한 시도들 기대해봅니다 😊 |
요구사항
배포링크
기본
로그인
회원가입
심화
스크린샷
멘토에게