영광스럽게도 포코와 헤인티의 리뷰를 둘 다 받을 수 있었어요. 엄청났습니다. 100개가 넘는 리뷰가 오고갔거든요!!
리뷰 반영하다가 울었습니다
엄청 두드려 맞았어요ㅋㅋ 근데 코드를 수정하면서 맞을만 했다고 생각합니다.
다음 미션에 바로 반영할 수 있을 정도로 많은 연습이 되었다고 생각해요. 오히려 좋아!!
const template = videoStorage.getVideoDataList().map(videoData => {
return `템플릿만들기`
})
// 한 번만 DOM을 만들어줍시다!
this.$storedVideoList.insertAdjacentHTML('beforeend', template.join(''));
반복문으로 template을 전부 만들고 나서 innerHTML, insertAdjacentHTML
해주는 작업은 한 번만 할 수 있도록 합시다.
최대한 element에 id를 부여해서 가져오도록 합시다.
this.renderSwitchedVideoData(storedList[storedList.length - 1]);
storedList.length - 1
를 왜하는지 알 수 있나요? 제 3자가 읽어도 문제가 없을 정도의 구체화를 해줍시다.
// 최소한 이렇게요!
const switchedVideo = storedList.length-1;
// 적어도 바뀐 비디오를 재렌더링한다고 느낌이 오겠죠?
if(this.$videoList.scrollHeight - this.$videoList.scrollTop <= this.$videoList.offsetHeight + EVENT.SCROLL.OFFSET
) {
// 무한 스크롤...
}
// 위보다는 이렇게!
const isScrollBottom = this.$videoList.scrollHeight - this.$videoList.scrollTop <= this.$videoList.offsetHeight + EVENT.SCROLL.OFFSET;
if(isScrollBottom) {
// 무한 스크롤...
}
parseClickedData(clickedVideo)
vs
parseVideoInfo(videoInfo)
과연 이 메서드 네이밍에 Click이라는 유저 행위가 포함되는 것이 맞을까요? 고민해봅시다!
const videoId = clickedVideo.children[4].dataset.videoid;
const publishedAt = clickedVideo.children[3].textContent;
const title = clickedVideo.children[1].textContent;
const url = clickedVideo.children[0].src;
const channelTitle = clickedVideo.children[2].textContent;
vs
const [thumbnailImg, title, channelTitle, publishedAt, videoId] = videoInfo.children;
// showType이라는 플래그는 막 변할 수 있쬬? 매우 위험한 상태
export default class MainView {
constructor() {
this.registerDOM();
this.renderStoredVideoList();
this.showType = VIDEO_TYPE.WATCH_LATER;
----------------------------vs----------------------------
this.#showType = VIDEO_TYPE.WATCH_LATER;
get showType(type) {
return tihs.#showType
}
set showType(type) { // type은 'watch-later', 'watched' 값이 들어올 것으로 기대합니다.
if (this.#showType === type) { // 만약 타입이 그대로라면 변경 x
return;
}
if (type !== VIDEO_TYPE.WATCH_LATER && type !== VIDEO_TYPE.WATCHED) { // 'watch-later', 'watched' 둘 다 아니면 변경 x
return;
}
this.#showType = type;
}
추가적으로 Typescript에서 showType을 위한 타입을 지정해주면 더 안전할 것 같다는 생각이 드네요.
getDataIndexInList(videoId) {
let dataIndex = 0;
this.getVideoDataList().forEach((videoData, idx) => {
...
}
}
----------------------------vs----------------------------
getDataIndexInList(videoId) {
let dataIndex = 0;
this.getVideoDataList().findIndex((videoData) => {
...
}
}
findIndex라는 좋은 메서드가 있네요. forEach를 생각하기 이전에 문서를 참고해서 만들어봅시다!
Array 내장 메서드 MDN
파싱하는 과정이 있어서 임의대로 mock Data를 변경해줬어요.
publishedAt: '2021-10-14T19:06:42Z',
// 위의 내용을 아래처럼 변경해줬어요.
publishedAt: '2021년 10월 14일',
하지만 혼났습니다.
기획자가 목데이터 던져줄때마다 한땀한땀 바꾸실건가용?
바로 인정... 바꾸지 맙시다!
if (checkRendering) {
this.$emptyListImage.classList.remove(DOM_STRING.HIDE);
return;
}
this.$emptyListImage.classList.add(DOM_STRING.HIDE);
----------------------------vs----------------------------
this.$emptyListImage.classList.toggle(query, condition);
하지만 언제나 toggle을 쓰는건 별로라고 느꼈어요. (예를 들면 snackBar를 사용할 때... 반복적으로 snackBar가 호출되면 쓸데없이 계속 toggle이 되더라구요.)
if([...event.target.classList].includes(DOM_STRING.VIDEO_ITEM_SAVE_BUTTON))
----------------------------vs----------------------------
if(event.target.classList.contains(DOM_STRING.VIDEO_ITEM_SAVE_BUTTON))
공식문서를 읽는 습관을 들입시다.
localStorage.getItem
은 최소한으로 불릴 수 있도록 작업합시다.