문제발생

일단 요구사항에 따라 로그인 페이지를 만들어 보았다.

요구사항대로 동작은 하지만, 내가 짰어도 별로 좋은 코드는 아닌거 같았다.

리팩토링하고 싶은 욕구가 마구마구 나지만 아직 JS 에 익숙하지 않아서 코드 리뷰 받기 까지 미루었다.

그래서 코드 리뷰를 받고 설명도 들은 지금, 이전에 만들었던 로그인 페이지를 리팩토링을 해보았다.

 


문제해결

수정을 하고 나니 전반적으로 수정 이전보다 코드가 훨씬 깔끔해졌다.

이전보다 변경에 유연해졌고, 검증 로직을 추상화하여 다른 곳에서도 쓸 수 있을 정도로 재사용성이 올라갔다. 

에러메시지 출력을 input 태그의 텍스트 노드를 변경하는 방식으로 바꿔서 클래스를 추가, 제거 하는 부분도 깔끔해졌다.

코드 리뷰를 받고 수정한 내용을 정리하자면 아래와 같다.

  • 이메일 / 비밀번호 검증 로직 분리
  • 에러 메시지 출력 방식 변경

변경 전 HTML

<div>
  <label class="sign-input-label">이메일</label>
  <input
    class="sign-input-email"
    type="email"
    value=""
    placeholder="이메일"
  />
</div>
<span class="email-empty hidden">이메일을 입력해주세요.</span>
<span class="email-wrong hidden">올바른 이메일 주소가 아닙니다.</span>
<span class="not-valid-email hidden">이메일을 확인해주세요.</span>
<div class="sign-password">
  <label class="sign-input-label">비밀번호</label>
  <input
    class="sign-input-password"
    type="password"
    placeholder="비밀번호"
  />
  <button class="eye-button" type="submit">
    <img src="/images/eye-off.svg" />
  </button>
</div>
<span class="password-empty hidden">비밀번호를 입력해주세요.</span>
<span class="not-valid-password hidden">비밀번호를 확인해주세요.</span>
<div>
  <button class="signin-btn">로그인</button>
</div>

 

변경 후 HTML

<div>
  <label class="sign-input-label">이메일</label>
  <input
    class="sign-input-email"
    type="email"
    value=""
    placeholder="이메일"
  />
</div>
<span class="email-error-msg"></span>
<div class="sign-password">
  <label class="sign-input-label">비밀번호</label>
  <input
    class="sign-input-password"
    type="password"
    placeholder="비밀번호"
  />
  <button class="eye-button" type="submit">
    <img src="/images/eye-off.svg" />
  </button>
</div>
<span class="password-error-msg"></span>
<div>
  <button class="signin-btn">로그인</button>
</div>

변경 전 JS

const signinBox = document.querySelector(".signin-box");
const signinBtn = document.querySelector(".signin-btn");

const emptyEmail = document.querySelector(".email-empty");
const wrongEmail = document.querySelector(".email-wrong");
const emptyPassword = document.querySelector(".password-empty");
const notValidEmail = document.querySelector(".not-valid-email");
const notValidPassword = document.querySelector(".not-valid-password");

const emailInput = document.querySelector(".sign-input-email");
const passwordInput = document.querySelector(".sign-input-password");

const TEST_EMAIL = "test@codeit.com";
const TEST_PW = "codeit101";

function inputCheck(e) {
  const type = e.target.type;
  const value = e.target.value;
  let regex = new RegExp("[a-z0-9]+@[a-z]+.[a-z]{2,3}");

  if (type == "email") {
    if (Number(value) == 0) {
      emptyEmail.classList.remove("hidden");
      emailInput.classList.add("error");
    } else if (!regex.test(value)) {
      wrongEmail.classList.remove("hidden");
      emailInput.classList.add("error");
    }
  } else if (type == "password") {
    if (Number(value) == 0) {
      emptyPassword.classList.remove("hidden");
      passwordInput.classList.add("error");
    }
  }
}

function reset(e) {
  const type = e.target.type;

  if (type == "email") {
    emptyEmail.classList.add("hidden");
    wrongEmail.classList.add("hidden");
    notValidEmail.classList.add("hidden");

    emailInput.classList.remove("error");
  } else if (type == "password") {
    emptyPassword.classList.add("hidden");
    notValidPassword.classList.add("hidden");

    passwordInput.classList.remove("error");
  }
}

function validation() {
  const email = emailInput.value;
  const password = passwordInput.value;
  if (email == TEST_EMAIL && password == TEST_PW) {
    window.location.href = "/forder.html";
  } else {
    notValidEmail.classList.remove("hidden");
    notValidPassword.classList.remove("hidden");
    emailInput.classList.add("error");
    passwordInput.classList.add("error");
  }
}

function validationByEnter(e) {
  if (e.key === "Enter") {
    validation();
  }
}

signinBox.addEventListener("focusin", reset);
signinBox.addEventListener("focusout", inputCheck);
signinBox.addEventListener("keydown", validationByEnter);
signinBtn.addEventListener("click", validation);

변경 후 JS

const signunBox = document.querySelector(".signun-box");
const signinBtn = document.querySelector(".signun-btn");

const emailInput = document.querySelector(".sign-input-email");
const passwordInput = document.querySelector(".sign-input-password");
const passwordCheckInput = document.querySelector(".sign.-input-pa");

const emailErrorMsg = document.querySelector(".email-error-msg");
const passwordErrorMsg = document.querySelector(".password-error-msg");

const TEST_EMAIL = "test@codeit.com";
const TEST_PW = "codeit101";

const EMPTY_EMAIL_MSG = "이메일을 입력해주세요.";
const INVALID_EMAIL_MSG = "올바른 이메일 주소가 아닙니다.";
const LOGIN_FAIL_MESSAGE_EMAIL = "이메일을 확인해주세요.";

const EMPTY_PASSWORD_MSG = "비밀번호를 입력해주세요.";
const LOGIN_FAIL_MESSAGE_PASSWORD = "비밀번호를 확인해주세요.";

function validateInput(inputEl, errorMsgEl, message) {
  errorMsgEl.textContent = message;
  if (message) {
    inputEl.classList.add("error");
    return;
  }
  inputEl.classList.remove("error");
  return;
}

function validateEmail() {
  const email_regex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/i;

  if (emailInput.value === "") {
    return validateInput(emailInput, emailErrorMsg, EMPTY_EMAIL_MSG);
  }
  if (!email_regex.test(emailInput.value)) {
    return validateInput(emailInput, emailErrorMsg, INVALID_EMAIL_MSG);
  }
  return validateInput(emailInput, emailErrorMsg, "");
}

function validatePassword() {
  if (passwordInput.value === "") {
    return validateInput(passwordInput, passwordErrorMsg, EMPTY_PASSWORD_MSG);
  }
  return validateInput(passwordInput, passwordErrorMsg, "");
}

function validatePasswordCheck() {
  if (passwordCheckInput.value === "") {
    return validateInput(passwordInput, passwordErrorMsg, EMPTY_PASSWORD_MSG);
  }
  return validateInput(passwordInput, passwordErrorMsg, "");
}

function signin() {
  if (emailInput.value == TEST_EMAIL && passwordInput.value == TEST_PW) {
    window.location.href = "/forder.html";
  } else {
    validateInput(emailInput, emailErrorMsg, LOGIN_FAIL_MESSAGE_EMAIL);
    validateInput(passwordInput, passwordErrorMsg, LOGIN_FAIL_MESSAGE_PASSWORD);
  }
}

function validationByEnter(e) {
  if (e.key === "Enter") {
    e.preventDefault();
    signin();
  }
}

emailInput.addEventListener("focusout", validateEmail);
passwordInput.addEventListener("focusout", validatePassword);
signinBtn.addEventListener("click", signin);
signunBox.addEventListener("keydown", validationByEnter);

+ Recent posts