티스토리 뷰
//비전공자가 혼자 공부하는 공간입니다
//잘못된 정보가 있을 수 있어요
Vanilla JavaScript로 todolist와 같은 로직의 shopping list 를 구현해보았다.
❗️[문제 발견]
그런데 리스트를 수정하는 과정에서 오류가 발생했다.
script.js:487 Uncaught DOMException: Failed to execute 'replaceChild' on 'Node': The node to be removed is no longer a child of this node. Perhaps it was moved in a 'blur' event handler?
at updateTitle (http://127.0.0.1:5501/script.js:487:24)
at HTMLInputElement.<anonymous> (http://127.0.0.1:5501/script.js:469:13)
해당 부분에 대한 코드이다.
// 수정 버튼 누르면 리스트 제목 변경
function handleListEdit(e) {
e.preventDefault(); //button의 기본 동작인 전송(submit)을 방지하기 위함
const addedList = this.parentNode;
const addedLiTitle = addedList.querySelector('.list-title');
if (addedLiTitle.tagName.toLowerCase() === 'h3') {
const input = document.createElement('input');
input.value = addedLiTitle.textContent;
// 키보드의 Enter를 누를 경우 제목 업데이트
input.addEventListener('keydown', e => {
if (e.key === 'Enter') {
updateTitle(input, addedLiTitle);
}
});
// onBlur 이벤트를 사용하여 input 외부를 클릭할 때 제목 업데이트
input.addEventListener('blur', () => {
updateTitle(input, addedLiTitle);
});
addedLiTitle.parentNode.replaceChild(input, addedLiTitle);
input.focus();
}
}
// 제목 업데이트 함수
function updateTitle(input, addedLiTitle) {
const newTitle = input.value;
addedLiTitle.textContent = newTitle;
input.parentNode.replaceChild(addedLiTitle, input);
}
🤔 [문제의 원인]
keydown 이벤트와 blur 이벤트가 중첩되어 동시에 발생해서 그런 것 같다.
Enter 키를 눌러 제목을 업데이트하면, keydown 이벤트가 발생하고 그 후에 blur 이벤트도 발생한다.
그래서 updateTitle (제목 업데이트) 함수가 두 번 호출되어 오류가 발생한 것 같다.
✅ [문제 해결]
상태 변수 isUpdatingTitle 을 사용하여
keydown 이벤트가 실행될 경우, blur 이벤트의 실행을 중단하고
blur 이벤트가 실행될 경우, keydown 이벤트의 실행을 중단해서 오류를 해결하였다.
// 수정 버튼 누르면 리스트 제목 변경
let isUpdatingTitle = false;
function handleListEdit(e) {
...생략
if (addedLiTitle.tagName.toLowerCase() === 'h3') {
const input = document.createElement('input');
input.value = addedLiTitle.textContent;
// 키보드의 Enter를 누를 경우 제목 업데이트
input.addEventListener('keydown', e => {
if (e.key === 'Enter') {
if (!isUpdatingTitle) {
isUpdatingTitle = true;
updateTitle(input, addedLiTitle);
}
}
});
// onBlur 이벤트를 사용하여 input 외부를 클릭할 때 제목 업데이트
input.addEventListener('blur', () => {
if (!isUpdatingTitle) {
isUpdatingTitle = true;
updateTitle(input, addedLiTitle);
}
});
addedLiTitle.parentNode.replaceChild(input, addedLiTitle);
input.focus();
}
}
// 제목 업데이트 함수
function updateTitle(input, addedLiTitle) {
const newTitle = input.value;
addedLiTitle.textContent = newTitle;
input.parentNode.replaceChild(addedLiTitle, input);
isUpdatingTitle = false;
}
이렇게 코드를 변경하였더니 오류메시지가 더 이상 뜨지 않는다
📖 [추가 학습]
논리 부정 연산자 - Logical NOT (!)
let isUpdatingTitle = false;
if (!isUpdatingTitle) {
isUpdatingTitle = true;
updateTitle(input, addedLiTitle);
}
!는 값의 반대되는 것으로 알고 있었는데 갑자기 너무 헷갈려서 이해하는데 시간이 조금 걸렸다.
isUpdatingTitle이 false이므로 (!isUpdatingTitle)은 그에 반대되는 isUpdatingTitle = true 라고 생각했다.
근데 만약 isUpdatingTitle이 true 라면, isUpdatingTitle을 true라고 해주는 것이 이해가 되지 않았다. 그 말이 그 말 아닌가...
그래서 지피티와 계속 동문서답을 주고받다가 드디어 이해하게 되었다 !
나는 (!isUpdatingTitle) 을 the opposite of isUpdatingTitle = false 라고 이해해서 그런 것이었다.
그게 아니라 It's not that the isUpdatingTitle is false (It's not that the title isn't being updated)라고 이해하면 되는 거였다.
그리고 이 문장은 true ! 값이 아닌 참이니까
조건에 맞다면 isUpdatingTitle의 값을 true로 할당해주는 것!
시간은 조금 걸렸지만 그래도 제대로 이해했으니 이제 찜찜함이 해결되었다.
//비전공자가 혼자 공부하는 공간입니다
//잘못된 정보가 있을 수 있어요
'포트폴리오' 카테고리의 다른 글
left:50; transform: translateX(-50%);의 원리는 뭘까 (1) | 2023.04.08 |
---|---|
[디버깅] 체크박스 Input & Label 불일치 오류 고치기 (0) | 2023.03.08 |
checkbox hover기능 + 컬러 변경 (0) | 2023.02.27 |
[디버깅]특정 함수들을 하나의 페이지에서만 실행하게 하기 (1) | 2023.02.22 |
DOMContentLoaded 사용해서 오류 해결하기 (0) | 2023.02.14 |
- Total
- Today
- Yesterday
- 캐시오류
- 상태변수
- CSS게임
- 비전공자
- 로컬스토리지오류
- CSS선택자
- labelfor
- 화살표함수
- 즉시실행함수
- DOMapi
- 이벤트핸들링
- DOM자바스크립트
- dom조작
- DOM제어
- JavaScript
- 자바스크립트
- :nth-child
- translateX
- 프론트엔드독학
- 리액트
- VirtualDom
- 체크박스오류
- CSS
- 프로그래밍독학
- 코딩독학
- 변수스코프
- 가상돔
- vanillajs
- 논리부정연산자
- CSSDiner
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |