티스토리 뷰

//비전공자가 혼자 공부하는 공간입니다 

//잘못된 정보가 있을 수 있어요

 

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로 할당해주는 것!  

시간은 조금 걸렸지만 그래도 제대로 이해했으니 이제 찜찜함이 해결되었다. 

 

 

//비전공자가 혼자 공부하는 공간입니다 

//잘못된 정보가 있을 수 있어요