[노마드코더-바닐라 JS로 크롬 앱 만들기]todo.js (2)

2021. 1. 25. 18:08Projects/VanilaJS- To-Do 앱 만들기

728x90
반응형

★to-do를 저장하기

이제 to-do(할 일)를 저장하는 것부터 시작할 것이다.

그리고 to-do list(할 일 목록)는 array가 되어야 한다. 왜냐하면 할 일 항목이 많아질 수 있기 때문이다.

해야할 일을 하나만 저장하는 게 아니라 여러 개가 모인 목록으로 저장해야 하는 것이다.

 

const toDos = [];

toDos라는 이름의 빈 배열을 만들어 준다. 처음엔 빈 배열로 만들고, 해야할 일을 생성했을 때 그게 이 toDos라는 Array에 추가되도록 한다. 그러기 위해서 일단 toDoObj 라는 것을 만들어야 한다.

 

 const toDoObj = {
        text: text,
        id : toDos.length + 1 //맨 처음엔 toDos Array가 비어있으니까 id 값은 1일 것이다.
    }

toDos.push(toDoObj); //이렇게 push를 써서 array 안에 element 하나를 넣어줄 수 있다. 이 경우에는 toDos Array안에 toDoObj를 넣게 되는 것이다.

Object 타입으로 만든 이유는, 텍스트와 id값을 둘다 가지고 있는 요소를 만들기 위해 그런 것이다.(id값이 있어야 나중에 삭제가 되기 때문에)

id값이 toDos.length + 1인 이유는 id를 1부터 시작하려고 그런 것이다.

 

const newId = toDos.length + 1;

    const toDoObj = {
        text: text,
        id : newId //맨 처음엔 toDos Array가 비어있으니까 id 값은 1일 것이다.

    }

    toDos.push(toDoObj); //이렇게 push를 써서 array 안에 element 하나를 넣어줄 수 있다. 이 경우에는 toDos Array안에 toDoObj를 넣게 되는 것이다.

id 값을 조금 더 보기 좋게 만들기 위해서 newId로 만들어주었다.

 

function paintToDo(text){
    const li = document.createElement("li");
    const span = document.createElement("span");
    const delBtn = document.createElement("button");
    const newId = toDos.length + 1;


    delBtn.innerText = "❌";
    span.innerText = text;

    li.appendChild(span);
    li.appendChild(delBtn);
    toDoList.appendChild(li);

    li.id = newId; // li에게 id를 부여
    const toDoObj = {
        text: text,
        id : newId //맨 처음엔 toDos Array가 비어있으니까 id 값은 1일 것이다.
    }

    toDos.push(toDoObj); //이렇게 push를 써서 array 안에 element 하나를 넣어줄 수 있다. 이 경우에는 toDos Array안에 toDoObj를 넣게 되는 것이다.
    
}

또한, li에게도 id를 할당하고 싶다. 그래야 나중에 버튼을 클릭했을 때 어떤 li를 지워야 하는지 알 수 있을 거니까. li에 id를 추가한다.

여기까지 한 후 실행해서 todo를 만들어보면 li에도 id가 부여된 것을 볼 수가 있다.

 

//중간점검: 여기까지 했을 때에는 paintToDo(text)함수는 form에서 submit 동작을 했을 때 실행되며(handleSubmit 함수에 의해 호출) 입력한 todo 항목을 화면에 보여준다. 생성된 li에 id를 부여한다. 그리고 각 element는 객체타입인 toDoObj로 생성하여 toDos라는 배열에 저장한다.

왜 todo를 이런식으로 저장하는거야 하고 의문이 들 수 있는데 그 이유는 로컬 스토리지에도 todo를 저장해둬야하기 때문이다.

 

이제 saveToDos라는 함수를 만들 것이다.

saveToDos는 toDos라는 Array를 가져와서 로컬에 저장하는 일을 하게 될 것이다.

 

 

function saveToDos(){
    localStorage.setItem(TODOS_LS, toDos);
}

일단은 이렇게 만든다.

 

toDos.push(toDoObj); //이렇게 push를 써서 array 안에 element 하나를 넣어줄 수 있다. 이 경우에는 toDos Array안에 toDoObj를 넣게 되는 것이다.
saveToDos();

saveToDos함수는 paintToDo함수에서 호출된다. Push한 후에 호출을 하도록 해야 한다.

만약 push 이전에 호출을 해버리면 저장할게 없어진다. 그래서 toDos 안에 집어넣은 이후에 불러야 한다.

 

여기까지 하고 저장한 후 todo를 만들고 localStorage를 보면 이렇게 객체 타입으로 저장된 것을 볼 수가 있는데 이런 걸 원했던게 아니다. 왜 그런걸까?

Local storage 에는 자바스크립트의 data를 저장할 수 없다. 오직 String만 저장할 수 있다.

(예를 들어 key값에 hello, value 값에 true로 저장한 후 console에서 hello를 가져와보면 boolean타입의 true가 아니라 string으로 “true”로 저장된다.)

자바스크립트는 local storage에 있는 모든 데이터를 String으로 저장하려고 한다.

그래서 우리는 우리의 object가 string이 되도록 만들어야 한다.

그걸 위해 아주 좋은 트릭인 JSON.stringify를 사용할 것이다.

 

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

JSON.stringify를 이용해서 saveToDos를 수정해주었다.

JSON.stringify는 자바스크립트 object를 string으로 바꿔준다. 이렇게 하고 실행을 해보면

이렇게 String으로 바뀌어서 저장된 것을 확인할 수 있다. 바라던 대로 되었다.

우린 이제 toDos를 저장하고 있는 것이다.(toDos – 배열임)

 

이제 toDos를 불러오는 작업을 다루어야 한다. (페이지를 새로고침해서 다시 들어와도 저장된 todo가 남아있도록 하려고 하는 듯)

새로고침을 해도 local storage에 toDos는 남아있다.

 

function loadToDos(){
    const loadedToDos = localStorage.getItem(TODOS_LS); //TODOS_LS = 'toDos'
    if(loadedToDos !== null){
        console.log(loadedToDos);
    }
}

loadToDos 함수로 이동하여 (loadedToDos가 null이 아니라면 불러오는) console.log를 이용해 loadedToDos를 확인해 보면,

이렇게 새로고침을 해도 보인다. 그런데 문제는 불러온게 String이라는 것이다.

그래서 JSON을 또 사용할 것이다. (JSON- JavaScript Object Notation의 줄임말로, 데이터를 전달할 때 자바스크립트가 그걸 다룰 수 있도록 object로 바꿔주는 기능인 셈이다. 자바스크립트의 object를 string으로 변환해주기도 하고(stringify) , string을 object로 바꿔주기도 한다.(parse))

 

function loadToDos(){

const loadedToDos = localStorage.getItem(TODOS_LS); //TODOS_LS = 'toDos'
    if(loadedToDos !== null){
        console.log(loadedToDos);
        const parsedToDos = JSON.parse(loadedToDos);
        console.log(parsedToDos);
    }
}

위와 같이 작성해준 후 parse(String ->Object)를 하기 전과 후를 console로 찍어보면

이렇게 parse를 하면 객체로 바뀌어 전달되는 것을 알 수가 있다.

 

이제 뭘 해야하나면, parsedToDos를 화면에 보여주어야 한다. 그러니까 local Storage에서 불러온 것을 이 화면 상에 써주는 것이다.

이제 뭘 할거냐면 모든 to-do 항목들에 대해서, 즉 parsedToDos의 안에 있는 것들에 대해서 paintToDo 함수를 실행할 것이다.

그 전에 먼저 forEach에 대해 설명을 하자면 forEach는 array가 가진 것으로 기본적으로 함수를 실행하는데 array에 담겨있는 것들 각각 한번씩 함수를 실행시켜 준다.

우리는 함수를 바로 괄호 안에서 만들거고 지금 만들 이 함수를 parsedToDos에 있는 것들 각각에 대해 실행해줄 것이므로 그 각각을 toDo라고 칭할 것이다.

(원래 forEach라는게 array.forEach(function(element) {

}) 이기 때문에 반복문에서 i 처럼 element자리에 toDo가 들어갔다고 보면 된다)

 

function loadToDos(){

    const loadedToDos = localStorage.getItem(TODOS_LS); //TODOS_LS = 'toDos'

    if(loadedToDos !== null){

        const parsedToDos = JSON.parse(loadedToDos);

        parsedToDos.forEach(function(toDo){

            console.log(toDo.text);

        })

    }

}

일단은 이렇게 작성해서 console.log로 나타내보면 텍스트만 뜨도록 할 수 있다. parsedToDos에 들어있는 각자의 text들이 console.log된 것을 볼 수 있다. 이렇게 forEach가 작동하는 것이다. (당연히 함수를 따로 선언하고 forEach 괄호 안에는 함수 이름만 넣어서 다른 애들처럼 그렇게 작성할 수도 있다.)

 

function loadToDos(){

    const loadedToDos = localStorage.getItem(TODOS_LS); //TODOS_LS = 'toDos'

    if(loadedToDos !== null){

        const parsedToDos = JSON.parse(loadedToDos);

        parsedToDos.forEach(function(toDo){

            paintToDo(toDo.text);

        })

    }

}

여기선 각각에 대해 paintToDo를 해주어야 한다.

정리하자면, toDos를 가져온 뒤, 가져온 것을 자바스크립트 object로 변환해주고 각각에 대해서 paintToDo라는 함수가 실행될 것이다.

 

여기까지 하면 todo항목을 만들었을 때 새로고침을 해도 저장이 되어있는 것을 볼 수가 있다!

728x90
반응형