
이번 글에서는 To Do List의 핵심 기능인 추가 / 삭제 / 수정 기능을 구현하면서 겪었던 고민과 과정들을 다뤄 보려고 합니다.
이전 글(2. 화면에 todo 렌더링하기)에 이어진 글입니다 :)
todo 추가 기능은 비교적 구현 난이도가 쉬운 편이었다.
전체 흐름은 입력값 검증 → todos 배열 업데이트 → 다시 렌더링 구조로 잡았다.
function addTodo() {
if (document.getElementById("input-value").value.trim() == "") {
// 1. 입력 input 값이 빈 값이라면 해당 input에 focus
document.getElementById("input-value").focus();
} else {
// 2. 작성한 내용의 객체를 todos 배열에 추가
todos.push({
id: todos.length,
contents: document.getElementById("input-value").value,
isDone: false,
});
// 3. todos 배열 렌더링
renderTodos(todos);
// 4. 추가 완료됐으면 input 값 초기화
document.getElementById("input-value").value = "";
}
}
todo 추가 기능은 아래와 같은 알고리즘으로 설계했다.
todos 배열에 추가 todos 배열을 다시 렌더링 삭제 기능은 처음 생각보다 고민이 많았다.
그래서 아래 두 가지 방법을 두고 고민했다.
isDelete 같은 프로퍼티를 추가해서 관리할지 todos 배열에서 해당 todo를 아예 제거할지 결론은 후자였다.
현재 서비스에서는 삭제된 todo를 다시 활용할 계획이 없었기 때문이다.
삭제 로직은 아래와 같이 설계했다.
todos 배열에서 해당 id를 가진 요소를 찾아 splice(id, 1)을 호출했다 renderTodos(todos)로 다시 렌더링했다 하지만 예상치 못한 문제가 발생했다.
특이하게도, 순서대로 삭제하면 또 잘 동작했다.
원인은 splice 메서드의 특성 때문이었다.
splice는 배열의 인덱스를 기준으로 동작하는데,
todo를 삭제하는 순간부터id !== index상태가 되어버렸다
즉,
id === index라서 문제가 없었고 이런 고민도 들었다.
“삭제 버튼 클릭 시, 해당 todo 객체로 바로 접근할 수는 없을까?”
하지만 구조적으로 어렵다는 걸 알게 됐다.
data-id 같은 식별자를 통해서만 연결할 수 있었다 이 과정에서
UI는 상태를 보여주는 결과물이고, 실제 데이터는 JS가 관리한다
라는 개념이 더 명확해졌다.
이번 구현에서 가장 많이 막혔던 부분이 수정 기능이었다.
span 태그 안에 todo 내용을 넣고 있었다 여기서 이런 고민이 들었다.
“클릭해서 수정하려면, 애초에 input 박스로 렌더링하는 게 맞지 않을까?”
그래서 todo 내용을 input 박스로 렌더링하는 방향으로 변경했다.
의도한 흐름은 다음과 같았다.
disabled → false로 변경 이를 위해 editTodo() 함수를 작성했다.
function editTodo(event) {
const targetEditButton = event.target;
targetEditButton.disabled = true;
const targetTodo =
event.target.closest('div').parentNode
.getElementsByClassName('todo-inputbox')[0];
targetTodo.disabled = false;
targetTodo.focus();
}
CSS는 아래와 같이 작성했다.
.edit-text {
font-size: 15px;
color: #aaa;
line-height: 1;
background-color: #eee;
padding: 6px;
border-radius: 3px;
}
.edit-text:disabled {
color: whitesmoke;
background-color: #ddd;
}
.edit-text:hover {
transition: 0.2s;
color: whitesmoke;
background-color: #ddd;
}
하지만 아무리 해도 disabled 스타일이 적용되지 않는 문제가 발생했다.
- 수정 버튼을
span태그로 구현했는데disabled속성은 모든 태그에서 지원되지 않았다
MDN 문서를 통해 확인했다.
출처 : https://developer.mozilla.org/ko/docs/Web/HTML/Reference/Attributes/disabled
해결 방법
→ span 태그를 button 태그로 변경했다
<button type="button" class="edit-button" onclick="editTodo(event)">
수정
</button>
다음으로 마주한 문제는 이것이었다.
function editTodo(event) {
if (event.target.disabled == true) {
event.target.disabled = false;
} else {
event.target.disabled = true;
}
}
이렇게 토글하려 했지만,
disabled가 되는 순간 버튼이 아예 클릭되지 않았다.
즉,
문제를 정리해보니 핵심은 이것이었다.
disabled 하나로 표현하려 했던 점 그래서 방향을 다음과 같이 바꿨다.
editing-button edit-button 이 방식이 훨씬 명확했고,
기능 / 상태 / 스타일이 조금씩 분리되기 시작했다.
이번 구현을 통해 느낀 점은 다음과 같았다.
다음 글에서는
을 다룰 예정이다.
현재 코드는 동작은 하지만, 아직 구조적으로 예쁘지는 않은 상태다.
조금씩 다듬어가며 발전시켜볼 생각이다.