지난 강의에서는 JSON.stringify()
메서드를 사용하여 JavaScript 객체를 문자열로 변환하고, JSON.parse()
메서드를 사용하여 JSON 문자열을 다시 JavaScript 객체로 변환하는 방법을 배웠습니다. 그러나 문제점은, toDos가 localStorage에 저장되어 있지만 브라우저를 새로고침하면 화면에 나타나지 않고, 새로운 내용을 작성하면 기존의 localStorage에 저장된 내용이 지워지고 새로 작성한 내용이 저장된다는 것입니다. 이 문제를 해결해 보겠습니다.
이전 강의에서 작성한 console.log
부분은 더 이상 필요하지 않기 때문에 지워줍니다. 지금 원하는 것은 parsedToDos
배열 내부에 있는 아이템들을 화면에 나타내고 싶은 것입니다. 그리고 이미 그 아이템들을 화면에 그려주는 paintToDo
함수가 있으며 이 함수가 필요로 하는 것은 newToDo
입니다.
if (savedToDos !== null) {
const parsedToDos = JSON.parse(savedToDos);
parsedToDos.forEach((item) => console.log("this is the turn of", item)); // 🎈
}
function paintToDo(newToDo) {
const li = document.createElement("li");
const span = document.createElement("span");
span.innerText = newToDo;
const button = document.createElement("button");
button.innerText = "❌";
button.addEventListener("click", deleteToDo);
toDoList.appendChild(li);
li.appendChild(span);
li.appendChild(button);
}
🎈 'item' 부분은 paintToDo
함수를 호출함으로써 쉽게 변경할 수 있습니다. 'item'은 사용자가 입력한 텍스트이며, 화면에 표시하려는 텍스트입니다. 그러나 이를 복잡한 코드로 작성할 필요 없이, 이미 화면에 'item'들을 그리는 함수인 paintToDo
를 호출하면 됩니다.
if (savedToDos !== null) {
// savedToDos가 localStorage에 존재할 경우
// 두 연산자가 같지 않거나, 데이터 타입이 다를경우 true를 반환
const parsedToDos = JSON.parse(savedToDos);
// localStorage에서 가져온 String을 JavaScript 객체를 반환
parsedToDos.forEach(paintToDo);
// paintToDo는 localStorage에 저장된 내용을 화면에 표시해 주는 역할
}
💡
parsedToDos.forEach(paintToDo)
는parsedToDos
배열에서forEach()
메소드를 호출하는 코드, 이 메소드는 배열의 각 요소를 순회하며, 각 요소마다paintToDo
함수를 실행,paintToDo
함수는 문자열 매개변수를 받아 HTML에서 새로운li
요소를 만들고 해당 문자열을 텍스트 내용으로 사용합니다.forEach()
메소드에paintToDo
를 인수로 전달함으로써,parsedToDos
배열의 각 항목마다paintToDo
를 호출하고 각 항목에 대해 HTML에서 새로운li
요소를 만듭니다.
기존에 저장되어 있던 내용에 새로운 내용을 추가한 후 localStorage를 확인해 보면, 새로운 내용은 저장되지만 기존에 저장되어 있던 내용은 여전히 없어지는 문제가 있습니다.
이런 문제가 생기는 이유는 웹 페이지가 시작될 때 toDos
배열이 항상 비어 있기 때문입니다. toDos
는 빈 배열이며, 이 배열은 사용자가 입력한 to-do 리스트를 담는 데 사용됩니다. 사용자가 새로운 to-do를 작성하면, 이 항목은 toDos
배열에 추가됩니다. 그리고 newToDo
를 작성하고 toDos
배열에 push될 때 새로운 to-do들만 포함하고 있는 배열을 저장합니다. toDos
배열은 이전의 to-do들은 가지고 있지 않고 새로운 to-do만 저장하기 때문에 기존에 작성했던 내용은 저장되지 않습니다.
const toDos = []; // X
let toDos = []; // O
해결 방법은 const
부분을 let
으로 변경해 업데이트가 가능하도록 만들고 localStorage에 이전에 작성한 to-do들이 저장되어 있는 경우, parsedToDos
를 toDos
에 할당하여 저장된 to-do를 복원합니다.
자바스크립트에서
let
은 변수를 선언하는 데 사용되는 키워드, 선언된 변수의 값을 언제든지 변경할 수 있지만const
는 상수를 선언하는 데 사용되는 키워드로, 한 번 선언된 상수의 값을 변경할 수 없습니다.
if (savedToDos !== null) {
const parsedToDos = JSON.parse(savedToDos);
toDos = parsedToDos;
parsedToDos.forEach(paintToDo
}
변경한 코드를 저장한 후 localStorage를 비우고, 로그인과 to-do 리스트를 다시 작성해서 결과를 확인해보면, 내용을 작성하고 새로 고침을 해도 화면에서 유지되는 것을 확인할 수 있으며, 새로운 내용을 추가해도 이전과 같이 새로운 내용만 저장되는 것이 아니라 기존 내용에 추가되는 것을 확인할 수 있습니다.
작성한 to-do 리스트를 삭제하고 화면을 새로고침하면 localStorage에 저장된 내용이 그대로 화면에 다시 출력되는 것을 볼 수 있습니다. 화면에서는 삭제를 했지만 localStorage에서는 아직 지우지 않았기 때문에 이러한 문제가 생깁니다.
이 문제는 다음 강의에서 수정해 보겠습니다.
const toDoForm = document.getElementById("todo-form");
const toDoInput = document.querySelector("#todo-form input");
const toDoList = document.getElementById("todo-list");
/** localStorage key값의 이름 */
let TODOS_KEY = "todos";
// newToDo를 submit 할 때마다 newToDo를 toDos라는 빈 배열에 계속 push 한다.
let toDos = [];
/** toDos의 내용을 localStorage에 저장하는 함수 */
function saveToDos() {
localStorage.setItem(TODOS_KEY, JSON.stringify(toDos));
// 로컬 스토리지에 toDos 배열을 JSON 문자열 형태로 저장한다.
// JSON.stringify() 메소드를 사용하면 객체나 배열을 문자열로 변환할 수 있습니다.
}
/** todo list가 제거되는 함수 */
function deleteToDo(event) {
const li = event.target.parentNode;
// 클릭된 요소의 부모 노드를 변수 li에 할당
li.remove();
// li 요소를 삭제
}
// 매개변수로 들어간 newToDo는 상수 newToDo와 관계없다.
/** todo list가 추가되는 함수 */
function paintToDo(newToDo) {
const li = document.createElement("li");
const span = document.createElement("span");
span.innerText = newToDo;
// span의 텍스트는 handleToDoSubmit() 함수에서 온 newToDo 텍스트가 된다.
const button = document.createElement("button");
button.innerText = "❌";
button.addEventListener("click", deleteToDo);
toDoList.appendChild(li);
li.appendChild(span);
li.appendChild(button);
}
function handleToDoSubmit(event) {
event.preventDefault();
// preventDefault()는 event의 기본 동작이 발생되지 않도록 막아준다.
// ex: submit event는 새로고침을 하는데 그 기능을 막아준다.
const newTodo = toDoInput.value;
// 입력한 값을 변수에 저장한다.
toDoInput.value = "";
// 입력창을 초기화한다.
toDos.push(newTodo);
// toDoInput.value의 값을 todos배열에 추가한다.
paintToDo(newTodo);
// newTodo의 입력값을 paintToDo() 함수에 넣어 화면에 출력한다.
saveToDos();
// localStorage에 toDos 배열을 JSON 문자열 형태로 저장한다.
}
toDoForm.addEventListener("submit", handleToDoSubmit);
/** localStorage에 저장된 key를 불러오는 변수 */
const savedToDos = localStorage.getItem(TODOS_KEY);
if (savedToDos !== null) {
// 만약 savedToDos가 null이 아니라면, savedToDos 변수에 저장된 데이터가 존재할 경우
// 두 연산자의 비교된 값이 값이나 유형에서 동일하지 않으면 'true'를 반환, 값과 유형이 동일한 경우 false를 반환
const parsedToDos = JSON.parse(savedToDos);
// JSON 문자열 데이터를 JSON.parse() 메서드를 사용하여 JavaScript 개체의 배열로 변환 후, parsedToDos 변수에 할당
toDos = parsedToDos;
// localStorage에 이전에 작성한 to-do들이 저장되어 있는 경우, parsedToDos를 toDos에 할당하여 저장된 to-do를 복원한다.
parsedToDos.forEach(paintToDo);
// parsedToDos 배열의 각 요소에 대해 paintToDo 함수를 실행
}