본문 바로가기

TIL LIST/JavaScript

[chrome app 코딩 챌린지] 3. 로그인 값 기억하기

localStorage는 web storage 중 하나로 서버에 데이터를 저장하는 방식이 아닌 웹 브라우저 상에서 데이터를 저장할 수 있는 방식이다. 키와 값으로 데이터가 이루어져 있으며 이런 형식으로 이루어져 있다.

localStorage.setItem("key", value); // > setItem 
// > getItem, removeItem("key");
// > clear(); 클리어

로그인 화면에서 이름 데이터 값을 localStorage에 저장하고, 그 저장한 값을 불러들여 화면에 출력하는 방식을 사용하면 매커니즘 자체는 어렵지 않으나 후술할 문제 때문에 꽤 오랜 시간이 걸렸다.

코드 리뷰

<main class="main__user-interface hidden">
    <div class="user-interface__weather window">
        <div class="window__header">
            <span><span class="header__window-username"></span> - Weather</span>
            <img src="images/close-icon.png" alt="">
        </div>
    </div>

    <div class="user-interface__status-bar">
        <div class="status-bar__start"></div>
        <div class="status-bar__clock"><span>00:00</span></div> <!-- TIME 추가될 곳 -->
    </div>
</main>
const loginName = document.querySelector(".login__form input#name");
const windowUsername = document.querySelector(".header__window-username")

const greeting = document.querySelector(".main__greeting"); // login
const userInterface = document.querySelector(".main__user-interface"); // user-interface

const HIDDEN_CLASSNAME = "hidden" 
const USERNAME_KEY = "username"

function onLoginSubmit(event) {
    event.preventDefault();
    greeting.classList.add(HIDDEN_CLASSNAME);
    const username = loginName.value;
    localStorage.setItem(USERNAME_KEY, username);

    paintLogins(username);
}

function paintLogins(username) {
    windowUsername.innerText = `${username}`;
    userInterface.classList.remove(HIDDEN_CLASSNAME);
}
const savedUsername = localStorage.getItem(USERNAME_KEY);

if (savedUsername === null) {
    greeting.classList.remove(HIDDEN_CLASSNAME);
    loginForm.addEventListener("submit", onLoginSubmit);
} else {
    paintLogins(savedUsername);
}
  • submit를 제출하면 호출되는 함수 onLoginSubmit에 username의 변수를 선언하고 그 값을 submit될 때 받아오는 값, 즉 name input의 값으로 작성해준다. (loginName의 value = loginName.value)
  • localStorage.setItem() 메서드에 "username"이라는 키와 username이라는 값을 추가한다. setItem은 키에 데이터를 씌우는 것이고, getItem과 removeItem은 키를 가져오거나 삭제하는 등 제어할 수 있다.
  • "username"이라는 string이 too much 반복 되고 있기 때문에 (대문자로) USERNAME_KEY 라는 변수에 값을 저장해준다.
  • windowUsername 은 웹에서 localStorage에 저장된 값이 출력되는 곳이다. innerText를 이용해 setItem 했던 username을 넣어주었다.

여기까진 단순하게 submit(로그인) 하고 → submit 하는 순간 name에 있는 값을 로컬 스토리지 값에 저장하고 → 그 저장된 값을 string으로 출력해주는 일련의 과정일 뿐이었다.

하지만 우리는 새로고침을 하거나 세션이 만료되지 않을 때에도 로그인을 유지하고 싶고 혹여나 세션이 만료된다면 (=로컬 스토리지의 값을 잃는다면) 다시 로그인 화면을 띄우고 싶다.

그럴 때 조건문을 사용해보는 거다. 컴퓨터야, 만약 내가 로컬 스토리지에 값이 없다면 로그인 화면을 띄울 거고, 그렇지 않다면 유저 화면을 보여줘. 마치 주문을 거는 것처럼.

 

  • 앞서 말했던 getItem은 키를 가져올 수 있다. localStorage의 username key는 이제 savedUsername 변수의 값이 되었다.
  • 만약(if) savedUsername의 데이터가 null 이라면(없는 정보를 받아옴), 즉 로컬 스토리지에 데이터가 없다면 로그인 화면의 hidden class를 지워 준다. 그리고 submit 이벤트 리스너를 넣어준다.
  • 그렇지 않다면(else) 유저 화면의 hidden class를 제거하고 innerText를 통해 string 값이 수정된다. 이 과정은 onLoginSubmit 에서도, 조건문에서도 사용되기 때문에 재사용성을 위해 paintLogins 라는 함수를 만들어 묶어주었다.
    • 함수 onLoginSubmit의 인자와 paintLogin의 인자가 다른 이유?
      paintLogin(savedUsername) 은 하는 일이 화면에 출력되는 일 뿐이다. (유저 화면, 유저 화면 내 스트링) 또 유저정보가 savedUsername 이라는 로컬 스토리지에서 getItem 하고 있다.
      onLoginSubmit(event)는 name이라는 id를 가진 input에서 오고 있다. (loginName.value) 

결과물

개 빡센 디버깅의 세계

로직은 정상적으로 짠 거 같은데 정상적으로 친 것 같은데 왜 동작이 안되는 거야?

성공적으로 로그인하고, localStorage에 데이터도 정상적으로 있는 거 확인. 음! 잘 굴러가는군? localStorage에 데이터가 있으면 유저 화면을 띄우고, 없다면 로그인 화면을 띄우는 실험을 위해 새.로.고.침! 

 

어? 어디갔지?

 

...

위에서부터 하나하나 읽으면서 어떻게 동작하는 지 파악하고, 모든 변수를 콘솔로깅 해보고, 줄 위치도 바꿔보았다. 그러면서 useless한 문도 지우기도 하고... 한참을 멍하게 모니터만 바라보다가 미묘하게 거슬리는 한 줄이 있어 보니 오타..... 쌍욕을 박고 수정하니 정상적으로 동작하더라. 고작 30줄 남짓의 짧은 코딩에도 이런 문제가 생기는 데 나중에 현업에 투입됐을 때 코드들을 어떻게 처리해야 할지 조금 두려워 졌다. 코딩은 금방, 디버깅이 진짜라는 말이 틀린 말은 아닌 것 같다.

 

그리고 이름은 처음 지을 때 잘 짓자. 변수명을 고치고 이벤트명을 고치는 과정에서 사람이 개입하게 되면 실수가 생기니까. 하지만 아직까지 이름 짓는 건 잘 못하겠다...

 

마무리하며

함수로 묶을 수 있는 문과 아닌 문은 무엇인가? 함수 이름 옆에 붙어있는 얘 (☞゚ヮ゚)☞ (), return, 전역변수, 지역변수, 함수의 인자는 무엇이며 자바스크립트 내부에서 값은 어떻게 반환이 되고 있는가? 등등 프로그래밍의 기초라 할 수 있는 이런 기본 개념이 너무 부족한 것 같다. 코드를 봐도 왜 이렇게 되는지 정확한 대답을 못내려서 답답하다. 나의 지식이 너무 얕고 기초가 너무 부실해. deep dive를 하루에 30분은 읽도록 해야겠다.