인프런 커뮤니티 질문&답변

이준석님의 프로필 이미지
이준석

작성한 질문수

Svelte.js [Core API] 완벽 가이드

반응성 구문 관련 질문

해결된 질문

작성

·

186

1

안녕하세요 훌륭한 강의 덕분에 Svelte를 잘 학습하고 있습니다. '반응성 구문' 학습 도중 잘 이해가 가지 않는 부분이 있어 질문을 남깁니다. 

먼저 반응성 구문은 tick을 적용하지 않는다면, 화면이 한 번 갱신되고 난 후에 실행이 된다고 이해했습니다. 

그런데, 선생님께서 보여주신 예제에서는 tick()을 적용하지 않은 상태에서도 화면 상의 double 값이 0 => 2로 변화하였습니다. 이에 의문이 남아 아래의 코드와 같은 실험을 해보았습니다. Assign 버튼을 클릭하였을 때 제가 예상한 작동 순서는 다음과 같습니다. 

0. assign 함수 실행

1.  count ++ 

2. console.log(double) => 콘솔 상에 0 출력, 아직 화면이 갱신되지 않았으니 반응성 구문 실행 x

3. assign 함수 종료

4. 화면 갱신

5. 화면이 갱신되었으니, count값에 의존하고 있는 반응성 구문 실행

-- 여기서부터 반응성 구문--

6. count가 1로 증가한 상태로 화면이 갱신되었으니 'id = count'인 태그는 1 출력

7. double에는 아직 새로운 값이 할당되지 않았으니 'id = double'인 태그는 0 출력

8. 'double = count * 2' 문장 실행 : double = 2

9. 문자열 'double' 출력

하지만 제 예상과는 다르게 'double = count * 2' 문장이 실행되기도 전에, 

let double_ = document.getElementById("double");

console.log(double_);

으로 인한 결과 값이 <h2 id="double">2</h2>로 출력되었습니다. 

즉, double이라는 변수가 2로 변경되기도 전에 화면 상의 double은 2로 렌더링 되었습니다.

위와 같은 현상의 원인이 무엇인지 궁금합니다.  (소스코드는 아래에 텍스트로 남기겠습니다. )

다시 한 번 양질의 강의에 감사의 말씀 드립니다.

코드

<script>

  import { tick } from "svelte";

  let count = 0;

  let double = 0;

  $: {

    let count_ = document.getElementById("count");

    let double_ = document.getElementById("double");

    console.log(count_);

    console.log(double_);

    double = count * 2;

    console.log("double!");

  }

  async function assign() {

    count++;

    console.log(double);

  }

</script>

<button on:click={assign}> Assign</button>

<h2 id="count">{count}</h2>

<h2 id="double">{double}</h2>

답변 2

2

이준석님의 프로필 이미지
이준석
질문자

감사합니다.

완벽히 이해되었습니다!

친절한 답변 다시 한 번 감사드리구, 계속해서 학습 이어나가겠습니다.

0

HEROPY님의 프로필 이미지
HEROPY
지식공유자

이준석 님 안녕하세요.

현상에 대해 간단하게 설명드리면,

Svelte는 반응형 데이터(count, double)의 최적화 실행을 위해 처리할 로직을 모아서 한 번에 실행합니다.

따라서 이해하신 코드의 흐름대로 처리되지 않습니다.

특히 count_, double_ 변수는 단순히 DOM 요소를 참조하는 것이기에, 이미 바뀐 결과가 출력되는 것이죠.(이것은 Svelte가 아닌 JavaScript DOM의 특징입니다)

그래서 실행 흐름을 작성하자면 다음과 같습니다.

1. assign 함수 실행

2. count++

3. console.log(double)

4. assign 함수 종료

5. 반응성 구문($:) 실행 시작

6. console.log(count_) => <h2 id="count">0</h2>

7. console.log(double_) => <h2 id="double">0</h2>

8. 반응성 구문($:) 실행 완료

9. 화면 갱신

위 흐름의 6번과 7번에서는 분명 요소는 0을 가집니다.

화면 갱신은 가장 마지막에 일어나기 때문인데요.

콘솔에는 <h2 id="count">1</h2>과 <h2 id="double">2</h2>가 출력되는 것은 위에서 말씀드린 것처럼 단순히 해당 요소를 참조만 하고 있기 때문에 최종 결과만 보이는 것입니다.

그래서 console.log(count_)가 아닌 console.log(count_.textContent)와 같이 출력하면 0이 나옵니다.

반응성 구문을 다음과 같이 작성해서 테스트해 보세요.

$: {

  let count_ = document.getElementById("count");

  let double_ = document.getElementById("double");

  if (count_ && double_) {

    console.log(count_.textContent);

    console.log(double_.textContent);

  }

  double = count * 2;

  console.log("double!");

}

결국 질문하신 것처럼 원하는 순서대로 실행하려면 다음과 같이 작성할 수 있습니다.

<script>

  import { tick } from "svelte";

  let count = 0;

  let double = 0;

  $: {

    updateDouble(count);

  }

  async function updateDouble() {

    await tick()

    let count_ = document.getElementById("count");

    let double_ = document.getElementById("double");

    if (count_ && double_) {

      console.log(count_.textContent);

      console.log(double_.textContent);

    }. 

    double = count * 2;

    console.log("double!");

  }

  async function assign() {

    count++;

    console.log(double);

  }

</script>

위 내용 확인해 보시고 혹시 이해가 되지 않으시면 다시 질문 남겨주세요~

좋은 하루 보내세요~😉

이준석님의 프로필 이미지
이준석

작성한 질문수

질문하기