<!-- [코드 4-1] App.svelte-->
<script>
let h1 = '<h1>hello world</h1>';
</script>
{@html h1}
@html 키워드를 통해 문자열 내부를 html으로 평가하여 보여준다. xss의 위험이 있으므로 문자열을 적절히 필터링하는 전처리가 필요하다.
<!-- [코드 4-2] App.svelte-->
<script>
let cnt = 0;
</script>
{@debug cnt}
<button on:click={ () => cnt++ }>up</button>
cnt값이 바뀔 때 마다 cnt의 값을 console.log()
없이도 개발자도구에 출력해준다. 개발자도구가 닫혀있다면 console탭에 로그가 쌓이기만 한다. 만약 개발자 도구가 켜있다며 로그가 쌓임과 동시에 코드가 일시정지된다.
JS의 원시데이터(숫자, 문자열, null, symbol, undefined 등)는 Immutable하다.(불변성) 한 번 메모리에 할당되면 변경될 수 없다. 원시데이터를 값으로 갖는 변수에 새 값이 할당된다면, 새로운 번지에 데이터를 할당 한 뒤 변수가 가리키는 번지를 변경한다.
객체(Object, Array 등)는 Mutable하다.(가변성) 메모리에 할당되었더라도 변경될 수 있다.
<!-- [코드 4-3] App.svelte-->
<script>
let arr = ['x', 'y'];
let obj = {
a : 123,
b : [1, 2],
};
function assign() {
arr.push('z');
obj.a = 456;
obj.b.push(3);
}
</script>
<button on:click={assign}>assign</button>
<h1>{arr}</h1>
<h1>{obj.a}</h1>
<h1>{obj.b}</h1>
위 코드에서 버튼을 누르면 arr는 값이 그대로이고, obj.a와 obj.b의 값만 변화한다.
arr.push('z')
는 대입연산이 없었으므로 반응성을 갖지 않는다. 아래 [코드 4-4]에서 해결해보자.obj.a = 456
은 새 값이 대입되었으므로 반응성을 갖는다. obj.b.push(3)
은 arr와 사실상 동일한 코드이지만, 이상하게도 반응성을 가졌다. [코드 4-5]에서 다시 살펴보자.<!-- [코드 4-4] App.svelte-->
<script>
let arr = ['x', 'y'];
function assign_1() {
arr = [...arr, 'z'];
}
function assign_2() {
arr.push('z');
arr = arr;
}
</script>
<button on:click={assign_1}>assign_1</button>
<button on:click={assign_2}>assign_2</button>
<h1>{arr}</h1>
arr에 하여금 반응성을 갖도록 하는 방법 두 가지를 작성했다. 둘 모두 대입연산을 포함한다는 공통점을 갖고있다.
<!-- [코드 4-5] App.svelte-->
<script>
let obj = {
a : 123,
b : [1, 2],
};
function change_a_and_b() {
obj.a = 456;
obj.b.push(3);
}
function change_only_b() {
obj.b.push(3);
}
</script>
<button on:click={change_a_and_b}>a and b</button>
<button on:click={change_only_b}>b</button>
<h1>{obj.a}</h1>
<h1>{obj.b}</h1>
문제의 obj.b.push(3)
을 살펴보자. change_a_and_b
를 실행하면 obj.b
가 반응성을 갖는다. 그러나 change_only_b
를 실행하면 obj.b
가 반응성을 갖지 못한다.
TIL 03 포스트에서 살펴본 바와 같이, 대입과 동시에 Re-render가 일어나는 것이 아니라 일정 단위로 Re-render가 일어난다. change_a_and_b()
를 통해obj.a = 456
이 실행되면 svelte는 obj.a
뿐 아니라 obj
전체를 갱신한다. 그 시점에서는 obj.a
와 obj.b
모두 값이 바뀌었으므로 화면으로 볼 때에는 둘 모두 Re-render된다. obj.b
는 영문도 모른채 obj.a
덕분에 반응성을 갖게 된 것이다.
<!-- [코드 4-6] App.svelte-->
<script>
let text = 'a';
let doubleText;
$ : {
doubleText = text + text;
console.log(doubleText.length, doubleText);
}
</script>
<h1 on:click={()=>{text=text+'a';}}>{text.length}{text}</h1>
$라는 이름의 label구문에 포함된 어떤 변수가 반응성을 가질 때, 해당 label구문을 실행한다.
반응성 구문의 trigger가 되는 변수가 label구문 안으로 몇depth를 들어가는지는(어떤 scope를 갖는지) 상관없다.
let doubleText;
$ : {
doubleText = text + text;
}
$ : doubleText = text + text;
블록없이 콜론 :
뒤에 바로 변수명을 명시하면, 별도 선언없이 doubleText
변수를 만든다. doubleText
는 text
의 반응성에 뒤이어 반응성을 갖는다.
$: text, (()=>{console.log(text);})
$: if(text==='aaaa'){console.log(text);}
$: for(let i=0; i<10; i++){
text;
console.log(i);
}