[JavaScript] To-do 리스트 만들기

혜린·2022년 3월 21일
0

JavaScript

목록 보기
7/21
post-thumbnail

📖 나는 JavaScript를 공부하며 DOM 조작에 있어 가장 자신이 없었으며 미숙했다. 그래서 바닐라JS로 크롬 앱 만들기를 듣게 되었다. 사용자가 입력한 값을 화면에 나타내는 것 뿐만 아니라 localStorage(데이터를 저장할 수 있음)에 저장하고, 삭제하고, 다시 불러오기도 하는 다양한 과정들을 이해할 수 있는 강의였다.



1. HTML 구조

<form id="todo-form">
  <input type="text" placeholder="Write a To Do and Press Enter" />
</form>
<ul id="todo-list">
  <!-- <li>
     <span>사용자가 입력한 to-do 내용</span>
     <button>삭제 버튼</button>
  </li> -->
</ul>

🛒 To-do 리스트에 필요한 것

  1. 사용자가 입력할 입력창 form, input
  2. 입력할 때마다 입력 내용을 보여줄 리스트 ul, li
  3. 입력내용을 삭제할 수 있는 버튼 button


2. 입력값을 화면에!

// HTML의 form, input, li 태그를 가져오기
const $toDoForm = document.getElementById("todo-form");
const $toDoInput = toDoForm.querySelector("#todo-form input");
const $toDoList = document.getElementById("todo-list");

// 화면에 to-do 나타내주는 함수
function paintToDo(newTodo) {
  const li = document.createElement("li");
  const span = document.createElement("span");
  li.appendChild(span);
  span.innerText = newTodo;
  $toDoList.appendChild(li);
}

// input창에 사용가 to-do 입력했을 때
function handleToDoSubmit(event) {
  event.preventDefault();
  const newTodo = $toDoInput.value;
  $toDoInput.value = "";
  paintToDo(newTodo);
}
$toDoForm.addEventListener("submit", handleToDoSubmit);

🚚 상세과정

  1. HTML의 form, input, li 태그 가져오기

  2. 화면에 to-do 나타내기
    ul안에 넣을 lispan태그 createElement()로 생성
    spanli의 자식이므로 appendChild()
    span에는 사용자가 값을 입력할 때마다 그 입력값을 저장해둔 변수 newTodo를 넣어주기
    liul의 자식이므로 appendChild()

  3. input창에 사용가 to-do 입력했을 때
    ✔ submit 했을 때의 기본동작(새로고침) 방지
    ✔ 사용자 입력값 변수에 저장 후, 빈칸으로 만들어주기
    ✔ 사용자 입력값 화면에 그리기

💥 문제점

화면에 입력값이 바로 나타나기는 하나, 새로고침 시 입력값은 모두 없어지고 삭제하고 싶은 입력값을 삭제할 수도 없다. 아래의 2가지를 해결해야 한다.
1. 내가 입력한 to-do 저장해두기 (새로고침해도 남아있음)
2. 내가 입력한 to-do 삭제하기



3. 데이터 관리

(1) JSON.stringify()

🎁 예제
const player = {name:"nico"};
JSON.stringify(player); // "{\"name\":\"hyerin\"}"

✔ 빈 배열에 사용자가 입력한 입력값을 저장해 localStorage에 저장하고자 한다. 하지만, localStorage는 문자만을 저장할 수 있다.
JSON.stringify()는 JavaScript 객체나 배열, 또는 어떤 JavaScript 코든건 간에 String으로 만들어준다. (값을 String으로 저장시켜주고자 할 때 쓰임)


(2) JSON.parse()

🎁 예제
// 처음 localStorage에 갖고 있던 것
localStorage.getItem('todos') // "[\"a\", \"b\", \"c\"]"

// 실제로 무언가를 할 수 있는 배열을 얻을 수 있음
JSON.parse(local.Storage.getItem('todos')) // ["a", "b", "c"]

JSON.parse()를 통해 문자열로 저장되어 있던 값을 다시 배열로 얻을 수 있다.


(3) JSON.parse()의 필요성

const savedToDos = localStorage.getItem(TODOS_KEY);
console.log(savedToDos);
if (savedToDos !== null) {
  const parsedToDos = JSON.parse(savedToDos);
  console.log(parsedToDos);
}

✔ savedToDos는 단순한 문자열 ["a", "b", "c"]
✔ parse후의 parsedToDos는 배열 ['a', 'b', 'c']



5. to-do 관리

(1) to-do 업데이트

// const로 변수를 선언하면 toDos가 업데이트 되지 않는다.
const toDos = [];

// let으로 바꾸어 toDos가 업데이트 될 수 있도록 해준다.
let toDos = [];

(2) 이전 to-do 복원

const savedToDos = localStorage.getItem(TODOS_KEY);
if (savedToDos !== null) {
   const parsedToDos = JSON.parse(savedToDos);
   // toDos를 파싱해온 ToDos로 업데이트해주기
   toDos = parsedToDos;
   parsedToDos.forEach(paintToDo);
}

💥 문제점
✔ 새로고침했을 때, 이전에 작성했던 to-do가 사라짐

💡 해결
✔ localStorage에 저장되있는 to-do가 있다면, 파싱해와서 화면에 그려주기


(3) to-do 삭제

function deleteToDo(event) {
  const li = event.target.parentElement;
  li.remove();
}

💥 문제점
✔ 화면상에서는 어떤 것을 지워야 할 지 알고 있지만, localStorage에서는 어떤 값을 지워야하는지 알 수 없다. 따라서 화면상의 삭제는 이루어지지만, localStorage 상의 삭제는 되지 않기 때문에 새로고침 시, 삭제한 내용이 반영되지 않는다

💡 해결
✔ 내가 삭제할 to-do가 어떤 것인지 구분할 수 있어야 한다.
✔ 현재 toDos는 배열의 형태로 저장되어 있다. 고유의 id를 주어 object로 만든다면 내가 삭제할 to-do가 무엇인지 구별해낼 수 있다.

const newTodoObj = {
      text : newTodo,
      id : Date.now();
}
toDos.push(newTodoObj);
paintToDo(newTodoObj);

💾 object 형태로 저장한 to-do

  • 이제 빈배열인 toDos에는 to-do내용과 id값이 객체로 저장된다.
function paintToDo(newTodo) {
  const li = document.createElement("li");
  // id를 추가
  li.id = newTodo.id;
  const span = document.createElement("span");
  // paintToDo는 객체를 받음 
  span.innerText = newTodo.text;
  const button = document.createElement("button");
  button.innerText = "❌";
  button.addEventListener("click", deleteToDo);
  li.appendChild(span);
  li.appendChild(button);
  toDoList.appendChild(li);
}

🎨 화면에 그려주는 함수 painToDo

  • object를 받는 형태로 수정해준다.
function deleteToDo(event) {
  // 화면상에서의 삭제
  const li = event.target.parentElement;
  li.remove();
  // localStorage에서의 삭제
  toDos = toDos.filter((toDo) => toDo.id !== parseInt(li.id));
  // to-do 저장함수
  saveToDos();
}

🔥 to-do 삭제 함수

  • 화면상에서도 지워주고, 데이터상에서도 지워주어야 한다는 점
  • toDos를 filter()해주는 과정을 통해, li.remove()되지 않은(삭제되지 않은) to-do들만이 toDos가 될 것
  • toDo.id는 문자열이고, li.id는 숫자이므로 이 둘의 타입을 맞춰주어야 함
function saveToDos() {
  localStorage.setItem(TODOS_KEY, JSON.stringify(toDos));
}

문자열로 변환시켜 to-do 저장하는 함수

  • 특정 to-do를 지웠다는 것을 localStorage에 반영시켜주어야 하기 때문에, to-do 삭제 함수인 deleteToDo()에서 데이터를 삭제한 뒤 saveToDos()를 실행시키는 것이다.


마무리

쉬지 말고 기록하라.
기억은 흐려지고 생각은 사라진다. 머리를 믿지 말고 손을 믿어라.

<다산 정약용>

📝 공부한 내용을 기록하며 복습하는 과정을 통해 내 것으로 소화시킨 적이 참 많다. 그걸 알면서도 여러 핑계들로 많이 미루기도 미루어왔다. 지금껏 줄곧 알고리즘 문제 풀이를 중점적으로 블로그에 기록해왔다. 나의 기억이 흐려지지 않도록 JavaScript와 React와 같이 현재 공부하고 있는 것들 역시 꾸준히 블로그에 기록해야지.

profile
FE Developer

0개의 댓글