-
[JavaScript] 투두리스트 만들기 - 생성한 아이템 저장하고 불러오기 (1)만학도 프로젝트/JavaScript TodoList 2024. 3. 1. 21:36
지난 글에서 할 일을 생성하는 기능을 만들었었는데요.
생성하는 기능이 잘 동작하긴 하는데, 페이지를 새로고침 하면 아이템들이 모두 사라져 버립니다.
이번에는 localStorage를 활용해서 아이템을 생성할 때 그 정보를 저장해 두고,
새로고침을 해서 페이지가 갱신될 때 localStorage에 저장된 정보를 가지고 와서 아이템들이 사라지지 않고 페이지가 갱신되기 직전의 모습을 유지할 수 있도록 해보려고 해요.
리팩터링
일단은 지난번에 작성했던 코드를 조금 수정해 보겠습니다.
수정하는 이유는, 앞으로의 코드들이 읽기, 수정, 삭제 기능들이 붙으면서 점점 더 복잡해질 예정이기 때문에 조금 더 의미를 명확하게 구분할 수 있도록 각 역할에 맞는 이름을 붙여주기 위해서예요.
일단은 handleFormSubmit 함수 안에서 과하다 싶을 정도(?)로 각각의 역할로 구분할 수 있는 로직들에 이름을 붙여주는 형태로 리팩터링 해보려고 합니다.
저는 크게 3가지로 나눴는데요.
- 첫 번째는 템플릿 태그를 활용해서 가상의 .todo-item을 만드는 역할 (생성)
- 두 번째는 만들어진 .todo-item을 #todoList에 넣어주는 역할 (추가)
- 마지막은 .todo-item을 추가하고 나서 todoInput을 초기화해 주는 역할 (인풋 초기화)
위 세 가지 역할을 각각 createTodoItem, addTodoItem, clearTodoInput으로 나눠줄게요.
const todoForm = document.getElementById('todo-form'); const todoInput = document.getElementById('todo-input'); const todoList = document.getElementById('todo-list'); const todoTemplate = document.getElementById('todo-template'); // 생성 const createTodoItem = (itemTitle) => { const todoItem = todoTemplate.content .cloneNode(true) .querySelector('.todo-item'); todoItem.querySelector('.item-title').textContent = itemTitle; return todoItem; }; // 추가 const addTodoItem = (itemTitle) => { const todoItem = createTodoItem(itemTitle); todoList.appendChild(todoItem); }; // 인풋 초기화 const clearTodoInput = () => { todoInput.value = ''; }; const handleFormSubmit = (event) => { event.preventDefault(); const inputValue = todoInput.value.trim(); if (inputValue === '') return; addTodoItem(inputValue); clearTodoInput(); }; todoForm.addEventListener('submit', handleFormSubmit);
생성은 추가와 같이 이뤄지는 거니깐, addTodoItem안에서 createTodoItem를 호출하도록 handleFormSubmit 함수를 수정했습니다.
저장 로직 만들기
이제 저장로직을 만들어 볼 텐데요.
로컬스토리지를 통해서 저장 로직을 만들 때 가장 먼저 할 것은 불러오는 환경을 구축하기입니다.
왜냐하면 저장할 때 어디에 저장할지를 분명히 해야 하기 때문이에요.
왠지 로컬스토리지를 전혀 모르시는 분들은 '어디냐니? 로컬스토리지에다 하는 거 아니야?' 하실 수도 있을 것 같은데,
로컬스토리지는 객체처럼 key:value 쌍으로 값을 저장하고 불러올 수가 있는 구조로 되어있어요.
그래서 어떤 키에다 값을 저장할지를 생각하고, 그 값을 불러오는 함수를 먼저 만들어 둘 거예요.
그래야 그 키 값에 새로운 값을 덮어쓸 수가 있거든요.
저는 여러 개의 .todo-item들의 정보를 저장해야 하니깐 배열의 형태로 아이템들을 다룰 거고, 그 배열을 'todos'라는 키로 관리해보려고 합니다.
// ... const STORAGE_KEY = 'todos'; const getTodos = () => { return JSON.parse(localStorage.getItem(STORAGE_KEY)) || []; }; ...
그래서 이렇게 로컬스토리지의 todos 값을 가져오는 getTodos함수를 만들어봤는데요.
로컬스토리지의 getItem 메서드로 'todos'에 접근해서 값이 있으면 JSON으로 파싱 해서 리턴해주고, 없으면 빈배열을 리턴해주는 함수입니다.
로컬스토리지의 키 값은 불러올 때도, 저장할 때도, 삭제할 때도 써야 하니깐 STORAGE_KEY로 따로 선언해 뒀어요.
자, 그러면 이제는 진짜 저장하는 saveTodoItem함수를 아래와 같이 만들어 주겠습니다.
// ... const STORAGE_KEY = 'todos'; const getTodos = () => { return JSON.parse(localStorage.getItem(STORAGE_KEY)) || []; }; const saveTodoItem = (todoItem) => { const todoData = { title: todoItem.querySelector('.item-title').textContent, }; const todos = getTodos().concat(todoData); localStorage.setItem(STORAGE_KEY, JSON.stringify(todos)); }; // ...
createTodoItem으로 만든 todoItem을 아규먼트로 saveTodoItem에 전달해 주면 다음과 같은 동작이 수행되는 건데요.
- title 값을 찾아서 todoData 객체를 완성합니다.
- 앞서 만든 getTodos를 활용해서 로컬스토리지에 저장된 값을 불러오고, 그 뒤에 todoData를 concat 메서드로 붙여서 todos 배열을 완성합니다.
- 새로운 아이템이 추가된 todos를 로컬스토리지에 저장합니다.
여기서 제가 단순히 todoItem들의 title만 감싸는 배열을 만들지 않은 이유는, 투두 아이템에 체크 상태도 함께 관리하기 위해서예요. 다음에 체크상태를 관리할 때 todoData에 프로퍼티를 더 추가할 예정입니다.
자, 그럼 이제 이 저장 로직을 아이템이 추가될 때 잘 실행시켜주기만 하면 될 것 같은데요.
addTodoItem 코드를 조금만 수정하고, handleFormSubmit 에서 실행하는 걸로 해보겠습니다.
그러면 다음과 같은 코드가 완성이 됩니다.
const todoForm = document.getElementById('todo-form'); const todoInput = document.getElementById('todo-input'); const todoList = document.getElementById('todo-list'); const todoTemplate = document.getElementById('todo-template'); const STORAGE_KEY = 'todos'; const getTodos = () => { return JSON.parse(localStorage.getItem(STORAGE_KEY)) || []; }; const saveTodoItem = (todoItem) => { const todoData = { title: todoItem.querySelector('.item-title').textContent, }; const todos = getTodos().concat(todoData); localStorage.setItem(STORAGE_KEY, JSON.stringify(todos)); }; const createTodoItem = (itemTitle) => { const todoItem = todoTemplate.content .cloneNode(true) .querySelector('.todo-item'); todoItem.querySelector('.item-title').textContent = itemTitle; return todoItem; }; const addTodoItem = (itemTitle) => { const todoItem = createTodoItem(itemTitle); todoList.appendChild(todoItem); return todoItem; // <- 여기서 생성한 아이템을 리턴! }; const clearTodoInput = () => { todoInput.value = ''; }; const handleFormSubmit = (event) => { event.preventDefault(); const inputValue = todoInput.value.trim(); if (inputValue === '') return; saveTodoItem(addTodoItem(inputValue)); // <- 여기서 실행! clearTodoInput(); }; todoForm.addEventListener('submit', handleFormSubmit);
이렇게 수정하면, addTodoItem 에서 추가된 아이템이 그대로 saveTodoItem 의 아규먼트로 전달되면서 화면에 아이템을 추가하고 저장하는 순서로 코드가 동작하겠죠?
단순히 저장하나 넣었는데도 코드가 이렇게나 많아지다니.. 그래도 각 동작들에 이름 붙이기를 잘해둬서 크게 어지럽진 않은 것 같아요.
아무튼 여기까지 코드를 실행해 보면, 투두 아이템이 새로 추가될 때마다 아이템들이 로컬스토리지에 잘 저장되는 걸 볼 수 있습니다!
이제 저장은 잘 되는 것 같죠?
급 마무리
사실 이번 포스트에서 저장하고 불러오는 것까지 하려고 했는데, 생각보다 글 쓰는 게 시간이 너무 오래 걸리기도 했고 쓰고 나니 저장만 하는데도 양이 꽤 되는 것 같아서 불러오기는 다음에 이어서 작성해 보도록 할게요!
아직도 새로고침 하면 다 사라지긴 하지만, 저장 기능은 완성이에요!
다음에는 저렇게 로컬스토리지에 저장된 정보를 불러와서 아이템들을 그려주는 기능을 완성해 보도록 하겠습니다.
당연히 질문이나, 의문점이 드는 부분이라거나 제가 실수를 했다거나, 혹은 좀 더 좋은 방향이 있다면 댓글 부탁드립니다.
더 좋은 글을 쓰고 제가 성장하는 데에도 큰 도움이 될 거예요! :)
감사합니다.
'만학도 프로젝트 > JavaScript TodoList' 카테고리의 다른 글
[JavaScript] 투두리스트 만들기 - 생성한 아이템 저장하고 불러오기 (2) (0) 2024.03.24 [JavaScript] 투두리스트 만들기 - 할 일 생성 기능 (2) 2024.02.24 [JavaScript] 투두리스트 만들기 - HTML 뼈대 잡기 (0) 2024.02.18