• 카테고리

    질문 & 답변
  • 세부 분야

    프론트엔드

  • 해결 여부

    미해결

화면분기와 액션함수

20.12.10 13:00 작성 조회수 132

5

안녕하세요,

강의 잘 듣고 있습니다.

CreateList.svelte 에서 window 이벤트가 먼저 먹히는 부분이 이해가 안되서요.

예상은 isEditMode 가 false 인 부분이 렌더링이 먼저되고 클릭시 isEditMode 가 true 로 되면서 use:autoFocusout={offEditMode} 이 액션부분이 실행이 되고.

액션에 바인딩된 함수가 실행후 인수로 전달한 offEditMode 가 실행이될거라 생각했습니다.

하지만 강의를 듣고 이해한 바로는 화면의 분기와 상관없이 처음 렌더링시 isEditMode 가 false 임에도 불구하고 true 일때의 use:autoFocusout={offEditMode} 도 먼저 실행되는것 처럼 보입니다.

따라서 처음 렌더링시 isEditMode 가 false 임에도 불구하고 위 코드블럭에서 먼저 액션이 미리 실행되어 window.addEventListener('click', focusoutListener); 가 먹혀서 발생되는 에러라고 정리하면 될까요?

화면 분기에 상관없이 미리 액션 함수가 읽히는것에 대해 이해가 안가서 질문 드립니다 이거는 스벨트 액션에만 해당하는 문제인가요?

감사합니다.

답변 4

·

답변을 작성해보세요.

3

안녕하세요~ 답변 감사드립니다.

올려주신 답글과 함께..장황하지만 제가 이해한 내용을 다시한번 확인받아도 되는지요?

문제브라우저에서 동작하는 (1)자바스크립트(2)Svelte의 반응성으로 나타나는 하나의 '현상'.

처음 isEditMode 가 false 일때 이벤트가 발생되면 button -> ......-> window 까지 버블링이되어 올라가는 동시에 (javascript) isEditMode 가 true 일때 요소가 생성이 되면서 액션 함수가 실행(svelte 반응성)되어 집니다.

여기서 문제는 액션함수 실행으로인해 연결된 두가지 이벤트 리스너들이 동작하게 되는데 먼저 el에 연결된 focousinListener 자체는 autuFocustout 이 연결된 요소자체에 바인딩이되어 여기선 실행되어지지 않고 window 에 바인딩된 이벤트만 발생합니다. 따라서 isEditMode 가 false 임에도 불구하고 window에 연결된 핸들러 focusoutListener(offEditMode)가 실행되면서 isEditMode는 false가 됩니다.

해결. setTimeout 을 통해 이벤트리스너들을  나중에 호출하자.

  setTimeout(() => {
    el.addEventListener('click', focusinListener);
    window.addEventListener('click', focusoutListener);
  }, 0);

우선 setTimeout() 을 통해서 setTimeout 안의 콜백함수가 먼저 콜 스택이아닌 백그라운드로 보내지게 하고 0 초후에 테스트큐로 보내집니다. 후에 이벤트 루프로 콜스택에있는 모든 함수가 실행된후에 테스트큐에있던 이벤트 리스너가 콜스택으로 보내진후에 동작한다고 이해 했습니다.

이로서 기존 콜스택에있는것을 모두 호출한 뒤에 나중에 이벤트핸들러들을 실행할수 있게됩니다. 다시말해 앞서 문제가 되었던 자바스크립트와 스벨트의 반응성으로 나타나는 현상을 분리는 시킨건데요.

정확하게 어떤것이 콜스택에 쌓이는지는 가늠이 안가지만.. 대략적으로 개념은 이렇다고 보는데요..

제대로 이해한건지 강사님의 의견을 듣고 싶습니다.

읽어주셔서 감사합니다.

감사합니다!

3

Wondam Jung 님 안녕하세요.

먼저 강의 잘 들어주셔서 감사합니다.

제 강의가 많은 도움이 되었으면 좋겠습니다.

~

일단 질문하신 내용의 핵심 키워드는 '콜 스텍'과 '이벤트 캡쳐링/버블링'입니다.

기본 개념은 아시지요?!

다음을 코드를 예시로 살펴보겠습니다.

위 예시에서 button 요소를 클릭하면, 콘솔에는 'Click 1'과 'Click 2'가 모두 출력됩니다.

우선 여기서 질문하신 내용 중 이 현상이 Svelte 액션에만 해당하는 문제가 아닌 것은 아시겠죠?!

그럼 과정을 살펴보겠습니다.

우선 button 요소를 클릭하면, window => document => html => body => button 순으로 캡쳐링이 일어납니다.

캡쳐링 마지막으로 button 요소에 이벤트가 전파(Propagation)되면 '핸들러A'가 실행되고 로직이 동작하죠.(콜 스텍 과정은 생략합니다)

그리고 button => ~생략~ => window 순으로 버블링이 일어납니다.

그런데 핸들러A가 실행되면서 이미 window에 이벤트를 추가했기 때문에, 최종 전파된 클릭 이벤트로 '핸들러B'가 실행됩니다.

그래서 결국 콘솔에는 'Click 1'과 'Click 2'가 모두 출력됩니다.

~

만약 이 현상이 원하는 방식이라면 문제가 없겠지만,

질문하신 내용과 유사하게 'Click 1'만 출력되는 것을 원한다면 문제가 되겠죠.

그래서 다음과 같이 event 객체가 가진 stopPropagation 메소드를 실행해서 수정할 수 있습니다.

역시 button 요소를 클릭하면 window => ~생략~ => button 순으로 캡쳐링이 일어납니다.

button 요소에 이벤트가 전파(Propagation)되면 '핸들러A'가 실행되고 로직이 동작하죠.

그런데 로직에 '버블링 전파 중지'(stopPropagation) 명령이 있습니다!

따라서 이제 더 이상 button => ~생략~ => window 순으로 버블링은 일어나지 않습니다.

~

위 내용이 이해가 되시나요?

이해가 되셨다는 전제로 다시 본 질문으로 넘어와서 설명해 보겠습니다.

만약 autoFocusout 액션(함수)에서 setTimeout을 사용하지 않았다고 가정해 보겠습니다.

~

'Add another card' 버튼을 클릭하면, window => ~생략~ => 버튼 순으로 캡쳐링이 일어납니다.

캡쳐링 마지막으로 '버튼'에 이벤트가 전파되면 onEditMode가 실행되고 isEditMode가 true가 됩니다.

그러면 Svelte의 반응성(Reactivity)을 통해 다음 로직이 아닌 isEditMode가 연결된 조건 블록({#if ...}) 내 요소부터 생성합니다.
(여기서의 '요소 생성'은 화면에 출력하는 것과는 별개입니다!)

요소가 생성되면 바로 use 디렉티브에 연결된 autoFocusout 액션이 실행되고,

그 내부의 el.addEventListener('click', focusinListener) 그리고 window.addEventListener('click', focusoutListener)도 실행되죠.

물론 focusinListener 핸들러에 e.stopPropagation() 코드가 있어 버블링이 일어나지 않을 것 같지만, 그것은 현재 과정이 모두 끝난 이후의 클릭 이벤트에 해당하는 얘기라서 현재 과정엔 영향이 없고요,

아무튼 이 과정이 끝나면 다시 버튼 => ~생략~ => window 순으로 버블링이 일어나고,

결국 이미 window에 연결된 핸들러 focusoutListener(offEditMode)가 실행되며 isEditMode는 false가 됩니다.

따라서 이 방식으로는 수정 모드가 될 수 없으며, 이 문제를 해결하기 위해 setTimeout을 사용하는 것입니다.

~

그래서 질문하신 내용은 '에러'가 아니고,

브라우저에서 동작하는 자바스크립트와 Svelte의 반응성으로 나타나는 하나의 '현상'입니다.

Wondam Jung 님의 질문 수준으로 짐작컨데,
setTimeout을 통해 실행을 지연시키는 개념은 이미 알고 계실 거로 생각하니 이만 줄이겠습니다.

혹시라도 이해가 안 되시는 부분은 다시 질문 주셔도 좋습니다.

알고 계실 확률이 높겠지만 답변과 관련한 추가 정보는 '자바스크립트 콜 스텍', '이벤트 버블링', '이벤트 캡쳐링' 등으로 검색해 보시면 잘 설명되어 있는 좋은 포스트가 많이 있습니다.

~

궁금증이 해소되셨길 바라며,

즐거운 하루 보내시길 바랍니다 :)

감사합니다.

1

Truestar님의 프로필

Truestar

2021.02.07

두분의 정리된 글 잘 읽었습니다.

질문을 작성하다 연관성이 떨어진다 싶어
새로 질문을 만들었습니다.

1

오! 정리해주신 내용을 읽어보니 확실히 이해하신 듯합니다!

제가 따로 코멘트할 부분이 없네요!

부족한 제 답변을 잘 이해해 주셔서 감사합니다 :)