20200922 TIL

ToastEggsToast·2020년 9월 23일
1

We!

목록 보기
23/33
post-thumbnail

인스타그램 클론코딩 리팩토링

리팩토링이란?

외부동작을 바꾸지 않으면서 내부 구조를 개선하는 방법으로, 소프트웨어 시스템을 변경하는 프로세스이다. 한마디로 예전에 썼던 코드 고쳐보기.

개인적으로 리팩토링을 할 때엔 이전 버전을 잘 유지시켜두거나 (한마디로 깃 관리 잘 하라는 것임), 주석 처리를 잘 해줘야한다는 것이다.
실제로 동기 한 명은 리팩토링 하다가 날렸다고 했다. 저런..

login.js

id, pw의 길이가 하나 이상일 때에만 로그인 버튼이 활성화 되도록

기존 로그인 확인 코드는

if (inputIdValueLength && inputPwValueLength) {
    button.disabled = false;
    button.style.cursor = "pointer";
    button.style.opacity = "100%";
    button.addEventListener("click", () => {
    	document.location.href = "../html/main.html";
    });
   }
if (!inputIdValueLength || !inputPwValueLength) {
   button.disabled = true;
   button.style.cursor = "initial";
   button.style.opacity = "40%";
 }

였다.

리팩토링으로 삼항연산자를 사용해볼것을 코멘트 받았고 결과는

inputIdValueLength && inputPwValueLength? (button.disabled = false) : (button.disabled = true);
if (button.disabled) {
	button.disabled = true;
	button.style.cursor = "initial";
	button.style.opacity = "40%";
}
if (!button.disabled) {
	button.style.cursor = "pointer";
	button.style.opacity = "100%";
	button.addEventListener("click", () => {
		document.location.href = "../html/main.html";
	});
}

가 되었다.
사실 길이적 측면에서는 그닥 차이는 없지만,
css요소를 주는 부분과, 버튼 제어 부분을 구분해서 확인할 수 있게 되었다!!!!

아이디에 "@"가 포함되어있고, 비밀번호가 5자리 수 이상일경우 로그인 버튼이 활성화

 inputIdValue.includes("@") && inputPwValue.length >= 5
      ? (button.disabled = false)
      : (button.disabled = true);

main.js

피드 댓글에 좋아요를 누를 수 있고, 삭제 또한 가능하게 구현하기.

정말 엄청나고 굉장한 뻘짓을 경험했고, 깃 버젼 관리의 중요성과..
리액트의 필요성을 굉장히 간절히 뼈저리게 경험하게 된 계기가 되었다.
(솔직히 지금도 하는 중이다)

let likeBtns = document.querySelectorAll(".likeBtn");
likeBtns.forEach((likeBtn) => {
  likeBtn.addEventListener("click", (e) => {
    let iconClass = e.target;
    iconClass.className === "xi-heart-o"
      ? (iconClass.className = "xi-heart")
     : (iconClass.className = "xi-heart-o");
  });
});

맨 처음 작성했던 코드이다.
다 좋았는데 새로 추가되는 element에 대해 이벤트가 입혀지질 않았다. 음.
그렇지. 그게 맞다. 그래서 다시 추가를 했다.

const likeIt = () => {
  let likeBtns = document.querySelectorAll(".likeBtn");
  likeBtns.forEach((likeBtn) => {
    likeBtn.addEventListener("click", (e) => {
      let iconClass = e.target;
      iconClass.className === "xi-heart-o"
        ? (iconClass.className = "xi-heart")
        : (iconClass.className = "xi-heart-o");
    });
  });
};

이런 function을 만들어서 el이 추가되는 마지막에 붙였다.
새로 추가된 el에는 작동이 잘 됐었다. 음. 아주좋아.
근데 추가되고 나면 기존 el들에 대한 이벤트가 작동이 안 됐다.
진심으로 코드를 전부 다시 짜볼까 고민했다.
그러다 발생한 문제. 갑자기 하트가 옆으로 밀어지고 갑자기 또 하트가 생겨버렸다..!

엄청 미묘하게 버튼이 눌리면 버튼 클래스가 바뀌면서 버튼에 하트가 만들어지면어 엉망진창 와장창창 되는 상황이 된것이었다..
처음엔 코드를 갈아엎고싶었는데.. 동현님과 경민님이 극구 만류해주셔서 참았습니다 :)
원인을 밤 10시에 찾았고 제 막차는 11시.. 결국 일단 집부터 갔습니다.

그리고 다음날 아침!!!! 오류를 해결하기 위해 만반의 준비를 하고 왔습니다

1. 버튼 영역이 아닌 i태그의 클래스를 수정하려고 했더니 => 버튼의 클래스가 변경되는 경우의 수가 발생함

인스타그램에 가서 svg 코드를 카피해왔다.
전에 어떻게 해결해야할까 고민할 때 동현님께서 아예 innerHTML을 변경하면 안 되느냐는 말씀을 해주셨었는데 그걸 svg코드를 변경하는데에 사용했다.
색상이 변하고 안에가 가득 차야하기 때문에 svg를 제어하고 하는 것 보다는 해당 편이 더 나을 것 같았다.

2. 새로 추가되는 엘리먼트에 이벤트 리스너를 추가하기

이거는 진짜 열심히 많이 고민했었다.
이전에 투두리스트를 만들 때에도 똑같은 문제점에 도달했었는데 그 때는 엘리먼트를 추가시키는 단계에서 다시 코드를 작성했었다.
이번에는 다른 방법이 없을까? DOM에서 엘리먼트의 추가 및 삭제 등을 감지하는 것을 캐치하는 JS가 없을까 찾아보게 되었고 묻고 다니고 그랬는데
결론은 리액트를 쓰는이유는 이런게 아닐까였다.
일반적으로 dom에 접근하는 방법도 아니고, 사용법도 생소했다.

결국 원래 하던 방식대로 엘리먼트를 추가하는 단계에서 다시금 리스너를 달아주는 작업을 했는데, 이번에는 함수를 활용해보았다.

기존에 존재하던 엘리먼트에도 이벤트 리스너를 달아줘야했고, 새로 추가되는 엘리먼트에도 추가해줘야했기 때문에 함수로 list를 불러와 각각에 이벤트를 달아주면 되지 않을까 하고 생각했다.

  let likeBtns = document.querySelectorAll(".likeBtn");
  likeBtns.forEach((likeBtn) => {
    likeBtn.addEventListener("click", (e) => {
      if (likeBtn.classList.contains("like")) {
        console.log("remove");
        likeBtn.classList.remove("like");
        likeBtn.innerHTML = `<svg fill="#262626" height="12" viewBox="0 0 48 48" width="12"><path d="M34.6 6.1c5.7 0 10.4 5.2 10.4 11.5 0 6.8-5.9 11-11.5 16S25 41.3 24 41.9c-1.1-.7-4.7-4-9.5-8.3-5.7-5-11.5-9.2-11.5-16C3 11.3 7.7 6.1 13.4 6.1c4.2 0 6.5 2 8.1 4.3 1.9 2.6 2.2 3.9 2.5 3.9.3 0 .6-1.3 2.5-3.9 1.6-2.3 3.9-4.3 8.1-4.3m0-3c-4.5 0-7.9 1.8-10.6 5.6-2.7-3.7-6.1-5.5-10.6-5.5C6 3.1 0 9.6 0 17.6c0 7.3 5.4 12 10.6 16.5.6.5 1.3 1.1 1.9 1.7l2.3 2c4.4 3.9 6.6 5.9 7.6 6.5.5.3 1.1.5 1.6.5.6 0 1.1-.2 1.6-.5 1-.6 2.8-2.2 7.8-6.8l2-1.8c.7-.6 1.3-1.2 2-1.7C42.7 29.6 48 25 48 17.6c0-8-6-14.5-13.4-14.5z"></path></svg>`;
        return;
      }
      if (!likeBtn.classList.contains("like")) {
        console.log("add");
        likeBtn.classList.add("like");
        likeBtn.innerHTML = `<svg fill="#ed4956" height="12" viewBox="0 0 48 48" width="12"><path d="M34.6 3.1c-4.5 0-7.9 1.8-10.6 5.6-2.7-3.7-6.1-5.5-10.6-5.5C6 3.1 0 9.6 0 17.6c0 7.3 5.4 12 10.6 16.5.6.5 1.3 1.1 1.9 1.7l2.3 2c4.4 3.9 6.6 5.9 7.6 6.5.5.3 1.1.5 1.6.5s1.1-.2 1.6-.5c1-.6 2.8-2.2 7.8-6.8l2-1.8c.7-.6 1.3-1.2 2-1.7C42.7 29.6 48 25 48 17.6c0-8-6-14.5-13.4-14.5z"></path></svg>`;
        return;
      }
    });
  });
};

그리고 길어진 코드.. (쮸륵

함수를 전역에 한 번 실행시켜주고, 엘리먼트가 추가되는 마지막 단계에서 다시 한 번 실행시켜주었다.
그러니까, 엘리먼트를 추가시키는 함수 바로 밑에 이 함수를 다시 불러왔다.

어 근데 여기서 궁금증이 발생.
코드는 위에서부터 아래로 읽어가는데 어떻게 아래에 있는 함수를 위에서 읽을 수 있는걸까..
내 추측이긴 하지만, 위에서 아래로 읽어내려가도 실제 엘리먼트를 추가시키는건 스크립트가 다 읽혀지고 난 뒤이기 때문에 가능한게 아닐까??

=> 멘토님께 물어보고 해결!!!
자바스크립트는 참조해야하는 것을 먼저 등록시킨뒤 스크립트를 실행시킨다.
그래서 내가 함수를 뒤에 작성하더라도 참조가 이미 되어있기 때문에 실행이 가능했던것!!! 스코프의 범위가 더 넓다!!!! 너무너무 신기하다ㅜㅜ

오늘의 뻘짓

  1. 함수를 새로 만들었다. 새로 만들었는데 처음에 됐는데 갑자기 안 됐다. 그래서 멘토님을 찾아 헤매다가 여쭤봤다. 이유를 찾았다. 함수 끝에서 함수를 다시 불러왔다. 이게바로.. 재귀함수...? (아니면 말고)

  2. 자이콘으로 아이콘을 불러왔었는데, 나는 그게 i태그에만 가능한 줄 알았지..
    미묘하게 i태그가 겹치지않는 버튼 태그가 클릭되었을 때 버튼에 또 아이콘이 생성되면서 진짜 엉망진창 와장창창.. 같이 코드 뜯어봐주시고 머리싸매주시고 해결하고 해결방법까지 같이 고민해준 13기 동현님, 경민님 제가 매우 애정합니다...

profile
개발하는 반숙계란 / 하고싶은 공부를 합니다. 목적은 흥미입니다.

0개의 댓글