노마드 코더_클론 코딩 - 크롬 앱 만들기(todo list편)

Todo list 코드들이 어려워서 한줄 한줄 리뷰를 해보려한다.

기억을 되짚어 가며 최대한 강의에서 진행한 순서대로 리뷰할 수 있도록 해보겠다.


전체 완성된 코드

const toDoForm = document.getElementById("todo-form");
const toDoInput = toDoForm.querySelector("input");
const toDoList = document.getElementById("todo-list");

const TODOS_KEY = "toDos";

let toDos = [];

function saveToDos() {
  // 배열상태인(localStorage는 배열 상태를 받을 수 없음) toDos를
  // String으로 바꾸고 그 값을 toDos라는 이름의 key에 넣어준다.
  localStorage.setItem(TODOS_KEY, JSON.stringify(toDos));
}

function deleteToDo(event) {
  const li = event.target.parentElement;
  li.remove();
  toDos = toDos.filter((toDo) => toDo.id !== parseInt(li.id));
  saveToDos();
}

function paintToDo(newTodo) {
  const li = document.createElement("li");
  li.id = newTodo.id;
  const span = document.createElement("span");
  span.innerText = newTodo.text;
  const button = document.createElement("button");
  button.innerText = "❌";
  button.addEventListener("click", deleteToDo);
  li.appendChild(span);
  li.appendChild(button);
  toDoList.appendChild(li);
}

function handleToDoSubmit(event) {
  event.preventDefault();
  const newTodo = toDoInput.value;
  toDoInput.value = "";
  const newTodoObj = {
    text: newTodo,
    id: Date.now(), // 랜덤한 번호(id)를 얻기 위해
  };
  toDos.push(newTodoObj);
  paintToDo(newTodoObj);
  saveToDos();
}

toDoForm.addEventListener("submit", handleToDoSubmit);

const savedToDos = localStorage.getItem(TODOS_KEY);

if (savedToDos !== null) {
  const parsedToDos = JSON.parse(savedToDos);
  toDos = parsedToDos;
  parsedToDos.forEach(paintToDo);
}

세부 코드

1. HTML 문서에서 Element를 반환하는 변수를 선언한다.

const toDoForm = document.getElementById("todo-form");
const toDoInput = toDoForm.querySelector("input");
const toDoList = document.getElementById("todo-list");

2. toDoForm 안의 input 박스를 submit 할 때 실행 할 이벤트를 생성하고

toDoForm.addEventListener("submit", handleToDoSubmit);

3. submit 되면서 실행 할 function을 생성한다.

function handleToDoSubmit(event) {
  event.preventDefault();
  const newTodo = toDoInput.value;
  toDoInput.value = "";
  paintToDo(newTodo);
}
  • event.preventDefault(); : submit 되면 JS는 브라우저를 새로고침하는게 기본값이기 때문에 event.preventDefault(); 를 통해 기본 값이 실행되지 않도록 한다.
  • const newTodo = toDoInput.value; : input 을 불러오는 상수 toDoInput에 사용자로부터 입력되는 값(value)을 새로 선언 할 상수 newTodo에 담아준다.
  • toDoInput.value = ""; : 그런데 submit을 해도 input 박스에 글이 없어지지 않고 계속 남아있다. submit을 하면 input 박스가 비워지게 하기 위해 toDoInput.value에 공백을 넣어준다.
  • paintToDo(newTodo); : 화면에 ToDo list를 띄워줄 function을 실행시킨다. (argument로 사용된 (newTodo)는 조금 있다가 (newTodoObj)로 바뀔 예정)

4. 아직 입력한 ToDo list가 화면에는 뜨지 않기 때문에 화면에 띄워줄 function을 작성한다.

function paintToDo(newTodo) {
  const li = document.createElement("li");
  const span = document.createElement("span");
  span.innerText = newTodo.text;
  const button = document.createElement("button");
  button.innerText = "❌";
  button.addEventListener("click", deleteToDo);
  li.appendChild(span);
  li.appendChild(button);
  toDoList.appendChild(li);
}
  • const li = document.createElement("li"); : HTML에 이미 생성해 둔 ul 에 JS 를 통해 li를 생성한다.
  • const span = document.createElement("span");
    span.innerText = newTodo.text;
    const button = document.createElement("button");
    button.innerText = "❌";
    li.appendChild(span);

    li.appendChild(button);
    : JS로 만든 li내부에 span태그와 button 태그를 생성하고 span 태그내부는 입력받은 todo 의 내용을 담고 button은 x 표시를 넣는다.
  • button.addEventListener("click", deleteToDo); : 버튼을 클릭하면 todo가 삭제되는 function이 실행되는 메서드를 작성한다.
  • toDoList.appendChild(li); : ul의 id 인 todo-list를 불러오는 상수 toDoList 에 span과 button이 포함된 li 상수를 자식 요소로 넣는다.

5. 화면에 ToDo list를 띄우는 건 되지만 새로고침을 하면 다 사라져 버린다. 그렇기 때문에 localStorage에 list를 넣어야 한다. (아까 리뷰한 코드는 주석 처리 했다.)

let toDos = [];

function saveToDos() {
  localStorage.setItem(TODOS_KEY, JSON.stringify(toDos));
}

function handleToDoSubmit(event) {
  // event.preventDefault();
  // const newTodo = toDoInput.value;
  // toDoInput.value = "";
   const newTodoObj = {
    text: newTodo,
    id: Date.now(), // 랜덤한 번호(id)를 얻기 위해
  };
  toDos.push(newTodoObj);
  paintToDo(newTodoObj);
  saveToDos();
}

function paintToDo(newTodo) {
  // const li = document.createElement("li");
  li.id = newTodo.id;
  // const span = document.createElement("span");
  // span.innerText = newTodo.text;
  // const button = document.createElement("button");
  // button.innerText = "❌";
  // button.addEventListener("click", deleteToDo);
  // li.appendChild(span);
  // li.appendChild(button);
  // toDoList.appendChild(li);
}

const savedToDos = localStorage.getItem(TODOS_KEY);

if (savedToDos !== null) {
  const parsedToDos = JSON.parse(savedToDos);
  toDos = parsedToDos;
  parsedToDos.forEach(paintToDo);
}
  • let toDos = []; : 사용자가 입력한 ToDo list 를 배열로 나열하기 위한 변수 toDos를 선언한다.
  • localStorage.setItem(TODOS_KEY, JSON.stringify(toDos)); : 배열상태인(localStorage는 배열 상태를 받을 수 없음) toDos를 String으로 바꾸고 그 값을 toDos라는 이름의 key에 넣어준다.
  • const newTodoObj = {
        text: newTodo,
        id: Date.now(), // 랜덤한 번호(id)를 얻기 위해
      };
    : 입력한 ToDo list 를 삭제하기 위해 각각 랜덤한 번호를 주어야 한다.
    왜냐하면 내가 클릭한 x버튼과 그에 해당하는 list가 일치해야 하는데 그러려면 서로 동일한 id를 갖고 있어야 비교해서 true 이면 삭제해야하기 때문이다. 
    그래서 list를 오브젝트로 만들어준다.
    이 코드를 handleToDoSubmit() function에 추가한다.
  • toDos.push(newTodoObj); : 배열로 만들어 둔 toDos 에 newTodoObj를 담는다.
  • paintToDo(newTodoObj); : paintToDo function에 argument로 newTodoObj를 보낸다.
  • saveToDos(); : 오브젝트(text, id)를 담은 toDos를 String 타입으로 바꾼 값을 localStorage의 toDos 키에 담아주는 function saveToDos()를 실행시켜 localStorage를 list를 작성할 때 마다 업데이트 하도록 한다.
  • const savedToDos = localStorage.getItem(TODOS_KEY); : localStorage에 있는 값들을 꺼내서 savedToDos 를 선언하며 담아준다.
  • const parsedToDos = JSON.parse(savedToDos); : localStorage 에 들어있는 값(JSON.stringify 로 문자열화 시킨 값)들을 꺼내는 savedToDos를 문자열을 JavaScript 객체로 변환해주는 JSON.parse 를 사용해 parsedToDos 에 할당한다.
  • toDos = parsedToDos; : JavaScript 객체로 변환된 값이 들어있는 parsedToDos 를 배열로 생성했던 toDos에 넣어준다.
  • parsedToDos.forEach(paintToDo); : JavaScript 객체로 변환된 값이 들어있는 parsedToDos에 배열의 각 요소에 대해 한 번씩 제공된 함수를 실행해주는 forEach를 사용해 각 배열의 요소 하나하나마다 paintToDo (화면에 list를 띄워주려고 만든 function)를 실행시킨다.

6. 이제 list 를 지우는 기능을 넣어야 한다.

function deleteToDo(event) {
  const li = event.target.parentElement;
  li.remove();
  toDos = toDos.filter((toDo) => toDo.id !== parseInt(li.id));
  saveToDos();
}
  • const li = event.target.parentElement; : 우선 x버튼을 누르면 해당 list가 화면상에서 삭제되도록 하기 위해 상수를 선언한다. parentElement 는 이벤트가 있었던 해당 요소의 부모 요소를 찾아준다. <button>의 부모는 아까 만든 코드로 인해 <li>이다.
  • li.remove(); : li 를 삭제한다. 그러면 화면에서 삭제버튼을 누른 list가 삭제된다. 하지만 localStorage에 남아있는 상태.
  • toDos = toDos.filter((toDo) => toDo.id !== parseInt(li.id)); : toDos(배열로 만들어둔)에 해당하는 toDo(parameter)의 id와 사용자가 삭제하고자 하는 li의 id가 일치하지 않는(!==) 것을 제외하고 나머지를 남기는 filter  메소드를 실행하고 그 값을 toDos에 할당한다.
  • saveToDos(); : 다시 그 toDos를 문자열로 변환해 localStorage에 담는 function인 saveToDos 를 실행해준다.

코드 리뷰는 다 한 것 같은데 여전히 머릿속이 뒤죽박죽이다.. 그래도 이 글을 작성하면서 Parameter 와 Argument의 차이를 알게 됐고 강의를 들으며 공부했던 것들을 한번 더 복습할 수 있었다.

근데 아직은 혼자서는 저렇게 절대 코딩 못할 것 같다..

'프론트엔드 > Javascript' 카테고리의 다른 글

D-Day 만들기!  (1) 2023.10.11
navigator.geolocation.getCurrentPosition(Ok, Error);  (0) 2023.10.03
filter()  (0) 2023.10.01
forEach()  (0) 2023.10.01
JSON.stringify(), JSON.parse()  (0) 2023.10.01