{#key} 블록은 표현식 값이 변경될 때 블록 내부의 마크업과 컴포넌트를 파괴하고 재생성하는 기능이다.
주로 트랜지션을 다시 실행시키거나, 특정 값에 종속된 컴포넌트를 강제로 다시 초기화하고 싶을 때 사용한다.
Vue의 경우 :key 속성을 변경하여 컴포넌트를 강제로 재마운트하는 패턴과 동일한 개념이다.
<script setup>
import Counter from './Counter.vue'
import { ref } from 'vue'
const resetKey = ref(0)
const reset = () => resetKey.value++
</script>
<template>
<button @click="reset">초기화</button>
<Counter :key="resetKey" />
</template>
React 또한 컴포넌트의 key prop을 변경하면 React가 해당 컴포넌트를 unmount/mount 처리한다.
import { useState } from 'react'
import Counter from './Counter'
function App() {
const [resetKey, setResetKey] = useState(0)
return (
<>
<button onClick={() => setResetKey(k => k + 1)}>초기화</button>
<Counter key={resetKey} />
</>
)
}
Svelte는 이를 마크업 영역에서 블록 형태로 제공한다는 점이 다르다.
{#key 표현식}
<!-- 표현식이 변경될 때마다 파괴 후 재생성되는 마크업 -->
{/key}
표현식 값이 바뀌면 블록 내부의 DOM과 컴포넌트가 새로 생성되며, onMount 등 라이프사이클 훅도 다시 실행된다.
일반적으로 트랜지션은 요소가 DOM에 추가되거나 제거될 때만 실행된다.
값이 변경되더라도 같은 요소가 유지되면 트랜지션이 다시 실행되지 않는다.{#key}로 감싸면 값 변경 시 요소가 파괴/재생성되어 진입 트랜지션이 다시 실행된다.
<script>
import { fade } from 'svelte/transition'
let count = 0
</script>
<button on:click={() => count++}>증가</button>
{#key count}
<div in:fade={{duration: 500}}>현재 값: {count}</div>
{/key}
버튼 클릭 시마다 count 값이 변경되면서 fade 트랜지션이 매번 재실행된다.
자식 컴포넌트의 내부 상태를 초기 상태로 되돌리고 싶을 때 사용할 수 있다.
컴포넌트가 새로 생성되므로 내부의 let 변수들이 초기값으로 재설정된다.
<script>
import Counter from './Counter.svelte'
let resetKey = 0
const reset = () => resetKey++
</script>
<button on:click={reset}>초기화</button>
{#key resetKey}
<Counter />
{/key}
Counter 컴포넌트 내부에 어떤 상태가 있더라도 버튼 클릭 시 새로 생성되어 모든 내부 상태가 초기화된다.
차트 라이브러리나 지도 라이브러리처럼 외부 인스턴스를 사용하는 컴포넌트의 경우, 데이터가 변경되어도 자체적으로 갱신되지 않는 경우가 있다.
이 때 {#key}로 감싸 데이터 변경 시 컴포넌트를 재생성하면 인스턴스도 함께 새로 만들어진다.
<script>
import Chart from './Chart.svelte'
export let chartData
</script>
{#key chartData}
<Chart data={chartData} />
{/key}
{#key}는 블록 내부를 통째로 파괴/재생성하기 때문에 비용이 큰 작업이다.
단순 값 동기화에는 적합하지 않으며, 반응성이 필요한 경우 $: 반응성 구문을 우선 고려해야 한다.
<!-- 잘못된 사용: 단순 값 변경에 key block 사용 -->
{#key user}
<p>{user.name}</p> <!-- $: 으로도 충분히 갱신됨 -->
{/key}
<!-- 올바른 사용: 트랜지션, 외부 인스턴스, 강제 재초기화 등 -->
{#key user.id}
<Profile {user} /> <!-- user 변경 시 Profile을 새로 생성 -->
{/key}
| 프레임워크 | 문법 | 동작 |
|---|---|---|
| Svelte | {#key 값}...{/key} |
마크업 영역의 블록을 파괴/재생성 |
| Vue | <Component :key="값"/> |
컴포넌트 props로 key 전달 시 재마운트 |
| React | <Component key={값}/> |
컴포넌트 props로 key 전달 시 unmount/mount |
Vue와 React는 컴포넌트 단위로만 가능하지만, Svelte의 {#key}는 컴포넌트가 아닌 마크업 영역에도 적용 가능하다는 차이가 있다.