이번 포스팅에서는 스벨트에서 사용하는 논리 블록에 대해 알아보자! 😀
스벨트는 조건에 따라 DOM을 화면에 나타낼지 나타내지 않을지 선택할 수 있는 조건문 블록을 제공한다. js와 동일하게 If, Else, Else-if 블록이 있다.
<script>
let user = {loggedIn: false};
function toggle() {
user.loggedIn = !user.loggedIn;
}
</script>
{#if user.loggedIn}
<button on:click={toggle}>
Log out
</button>
{/if}
{#if !user.loggedIn}
<button on:click={toggle}>
Log in
</button>
{/if}
Else 블록을 사용하여 좀 더 간단히 작성해 보자.
<script>
let user = {loggedIn: false};
function toggle() {
user.loggedIn = !user.loggedIn;
}
</script>
{#if user.loggedIn}
<button on:click={toggle}>
Log out
</button>
{:else}
<button on:click={toggle}>
Log in
</button>
{/if}
<script>
let x = 7;
</script>
{#if x > 10}
<p>{x} is greater than 10</p>
{:else if 5 > x}
<p>{x} is less than 5</p>
{:else}
<p>{x} is between 5 and 10</p>
{/if}
<script>
const arr = ['H', 'e', 'l', 'l', 'o'];
</script>
<ul>
{#each arr as item}
<li>{item}</li>
{/each}
</ul>
<script>
const arrLike = {
0: 'H',
1: 'e',
2: 'l',
3: 'l',
4: 'o',
length: 5
};
</script>
<ul>
{#each arrLike as item}
<li>{item}</li>
{/each}
</ul>
반복 가능한 객체는 아래와 같이 Each 블록을 사용할 수 있다.
- iterator
value와 done이라는 두 개의 속성을 가진 객체를 반환하는next
함수를 포함한 객체- iterable
이터레이터를 반환하는[Symbol.Iterator]
함수를 가진 객체
<script>
const iterable = {
[Symbol.iterator]: function*() {
yield 'H';
yield 'e';
yield 'l';
yield 'l';
yield 'o';
}
};
</script>
<ul>
{#each [...iterable] as item}
<li>{item}</li>
{/each}
</ul>
Each 블록의 배열이 비어 있을 경우, 예외 처리 표현을 위해 Else 블록을 사용할 수 있다.
<script>
let arr = [];
setTimeout(()=>{
arr = ['H', 'e', 'l', 'l', 'o'];
}, 1000)
</script>
<ul>
{#each arr as item}
<li>{item}</li>
{:else}
<li>빈 배열입니다.</li>
{/each}
</ul>
Each 블록의 두 번째 파라미터로 현재의 index를 알 수 있다.
<script>
const arr = ['H', 'e', 'l', 'l', 'o'];
</script>
<ul>
{#each arr as item, i}
<li>{i+1}: {item}</li>
{/each}
</ul>
<script>
const arr = [
{id: 1, value: 'H'},
{id: 2, value: 'e'},
{id: 3, value: 'l'},
{id: 4, value: 'l'},
{id: 5, value: 'o'}
];
</script>
<ul>
{#each arr as {id, value}}
<li>{id}: {value}</li>
{/each}
</ul>
Key는 Each 블록의 업데이트를 최적화하기 위해 사용된다. Key를 지정하면 업데이트되었을 때, 업데이트된 위치를 정확히 인지해 해당 DOM만 업데이트할 수 있다.
<script>
let arr = [
{id: 1, value: 'H'},
{id: 2, value: 'e'},
{id: 3, value: 'l'},
{id: 4, value: 'l'},
{id: 5, value: 'o'}
];
</script>
<ul>
{#each arr as item}
<li>{item.id}: {item.value}</li>
{/each}
</ul>
<button on:click={() => {arr = arr.slice(1)}}>
첫 번째 아이템 제거
</button>
위와 같이 작성했을 경우, 첫 번째 아이템이 제거되면 위에서부터 순차적으로 업데이트가 되고 마지막 아이템이 삭제되어 총 5번의 업데이트가 발생한다.
<script>
let arr = [
{id: 1, value: 'H'},
{id: 2, value: 'e'},
{id: 3, value: 'l'},
{id: 4, value: 'l'},
{id: 5, value: 'o'}
];
</script>
<ul>
{#each arr as item (item.id)}
<li>{item.id}: {item.value}</li>
{/each}
</ul>
<button on:click={() => {arr = arr.slice(1)}}>
첫 번째 아이템 제거
</button>
두 번째 코드처럼 Key를 지정하면 실제로 변경된 아이템만 업데이트되어 최적화된다. Key를 지정하는 방법은 {#each arr as item (item.id)}
와 같이 소괄호({...}) 안에 Key를 지정하면 된다.
스벨트는 내부적으로 Map 객체를 사용하기 때문에 Key에 숫자나 문자열뿐만 아니라 객체를 사용할 수도 있다. 즉, (item.id)
대신 (item)
으로 변경할 수도 있다!
<script>
let promise = getRandomNumber();
function getRandomNumber() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(Math.random());
}, 2000);
});
}
function handleClick() {
promise = getRandomNumber();
}
</script>
{#await promise}
<p>기다리는 중...</p>
{:then number}
<p>생성된 숫자는 {number}입니다.</p>
{:catch error}
<p style="color: red">{error}</p>
{/await}
<button on:click={handleClick}>생성하기</button>
{#await promise}...{:then number}
비동기 작업이 응답하기 전 화면에 노출되는 블록이다. 스켈레톤 UI를 사용하기 적당한 블록이다.
{:then number}...{:catch error}
비동기 작업이 응답하여 응답된 결과가 화면에 노출되는 블록이다. number는 Promise의 resolve 함수에 전달된 파라미터 값이다. Async 함수의 경우에는 반환값이다.
{:catch error}...{/await}
비동기 작업에서 에러가 발생할 때 화면에 노출되는 블록이다. error는 Promise의 reject 함수에 전달된 파라미터 값이다. Async 함수의 경우에는 throw로 반환된 값이다.
{#await promise then number}
<p>생성된 숫자는 {number}입니다.</p>
{/await}
비동기 작업에서 에러가 발생하지 않을 것을 확신할 수 있다면 Catch 블록을 생략할 수 있다.
Key 블록을 사용하면 블록에 사용한 표현식이 업데이트되면서 Key 블록의 내용들이 제거된 후 다시 추가된다.
<script>
import KeyComp from './KeyComp.svelte';
let value = 0;
</script>
{#key value}
<KeyComp {value} />
{/key}
<button on:click={() => value++}>Add Value</button>
개발자 도구로 살펴보면 첫 렌더링 시 컴포넌트가 생성되어 create 로그가 출력된 것을 볼 수 있다. Key 블록의 조건이 업데이트될 때마다 컴포넌트가 제거된 후 다시 생성된다. 때문에 Add Value 버튼이 클릭된 횟수만큼 로그가 출력된다.