$effect — 부수 효과 실행

$effect — 부수 효과 실행

$effect는 상태가 갱신될 때 실행되는 함수를 만드는 런이에요. 서드파티 라이브러리 호출, <canvas> 요소에 그리기, 네트워크 요청 같은 작업에 쓰여요. 브라우저에서만 실행되고 서버 사이드 렌더링 중에는 실행되지 않아요.

출처: https://svelte.dev/docs/svelte/$effect

<script>
  let size = $state(50);
  let color = $state('#ff3e00');
  let canvas;

  $effect(() => {
    const context = canvas.getContext('2d');
    context.clearRect(0, 0, canvas.width, canvas.height);

    // `color` 나 `size` 가 바뀌면 다시 실행됩니다
    context.fillStyle = color;
    context.fillRect(0, 0, size, size);
  });
</script>

<canvas bind:this={canvas} width="100" height="100"></canvas>

Svelte가 이펙트 함수를 실행할 때, 함수가 접근한 상태(파생 상태 포함)를 추적했다가 나중에 그 상태가 바뀌면 함수를 다시 실행해요. (untrack 안에서 접근한 값은 제외해요.)

일반적으로 이펙트 안에서 상태를 갱신하면 안 돼요. 코드가 더 복잡해지고 끝나지 않는 갱신 사이클로 이어지기 쉽거든요. 같은 일이라면 파생 상태를 쓰는 게 좋아요.

라이프사이클 이해하기

이펙트는 컴포넌트가 DOM에 마운트된 뒤, 그리고 상태 변경 후 마이크로태스크 시점에 실행돼요. 재실행은 배치(batch)로 처리돼서, colorsize를 같은 순간에 바꿔도 별도의 두 번 실행으로 이어지지 않아요. 이펙트는 부모 이펙트가 실행되는 동안 호출되기만 하면 컴포넌트 최상위뿐 아니라 어디서든 쓸 수 있어요.

이펙트는 teardown 함수를 반환할 수 있는데, 이 함수는 이펙트가 다시 실행되기 직전에 실행돼요. 예를 들어 setInterval을 만들고 반환 함수에서 clearInterval을 호출하면, 의존성이 바뀌거나 컴포넌트가 파괴될 때 정리가 돼요.

의존성 이해하기

$effect는 함수 본문 안에서 동기적으로 읽힌 반응형 값($state, $derived, $props)을 자동으로 의존성으로 등록해요. 함수 호출을 통한 간접 읽기도 포함해요. 그런 값들이 바뀌면 $effect가 재실행을 예약해요.

await 이후나 setTimeout 안처럼 비동기로 읽힌 값은 추적되지 않아요. 이펙트는 객체를 읽을 때 그 객체가 재할당된 때만 다시 실행되고, 객체 안의 속성이 바뀌는 것은 추적하지 못해요.

이펙트는 마지막 실행 때 읽은 값에만 의존해요. 조건부 코드가 있는 이펙트는 흥미로운 결과가 나올 수 있어요. conditiontrue일 때 color를 평가하면 condition이나 color가 바뀔 때 이펙트가 다시 실행되지만, conditionfalsecolor는 평가되지 않으므로 이펙트는 condition이 바뀔 때만 다시 실행돼요.

$effect를 쓰지 말아야 할 때

$effect는 기본적으로 탈출구(escape hatch)로 보는 게 좋아요. 분석(analytics)이나 직접 DOM 조작 같은 곳에 유용하고, 자주 쓰는 도구는 아니에요. 특히 상태를 동기화하는 데 쓰지 마세요. doubled = count * 2처럼 상태를 계산해서 맞춰야 한다면 이펙트가 아니라 $derived를 쓰세요.

$effect 안에서 $state를 꼭 갱신해야 하고 같은 $state를 읽고 써서 무한 루프가 난다면, untrack을 사용하세요.

더 알아보기