Svelte(스벨트) 란?
사용자 UI를 쉽게 만들 수 있게 해주는, 프론트엔드 프레임워크
Svelte의 특징
적은 코드로 작성할 수 있다
- 높은 가독성
- 개발 시간 단축
- 쉬운 리팩토링
- 쉬운 디버깅
- 작은 번들
- 낮은 러닝 커브
가상 dom이 없다 (바닐라 js 사용하므로 빠르다)
HTML 위에서 작동한다 ( Tailwind Css나, Django의 템플릿 과 비슷하게 작동 )
Svelte의 작동방식
우리가 Svelte 코드를 이용해 HTML에 모든 js, css를 구현하면,
Svelte는 Svelte 코드를 바닐라js, css로 변환해주고,
브라우저는 이를 사용해 화면을 만든다(렌더링)
Svelte 코드와, Vue, React 코드 비교 ( 동일한 기능 구현 )
1. React
import React, { useState } from 'react';
export default () => {
const [a, setA] = useState(1);
const [b, setB] = useState(2);
function handleChangeA(event) {
setA(+event.target.value);
}
function handleChangeB(event) {
setB(+event.target.value);
}
return (
<div>
<input type="number" value={a} onChange={handleChangeA}/>
<input type="number" value={b} onChange={handleChangeB}/>
<p>{a} + {b} = {a + b}</p>
</div>
)
};
2. Vue
<template>
<div>
<input type="number" v-model.number="a">
<input type="number" v-model.number="b">
<p>{{a}} + {{b}} = {{a + b}}</p>
</div>
</template>
<script>
export default {
data: function() {
return {
a: 1,
b: 2
};
}
};
</script>
3. Svelte
<script>
let a = 1;
let b = 2;
</script>
<input type="number" bind:value={a}>
<input type="number" bind:value={b}>
<p>{a} + {b} = {a + b}</p>
가상 DOM 이 없다! ( React, Vue와의 차이점 )
디핑이 없다. ( Diff 알고리즘을 사용할 필요가 없으므로 )
오버헤드가 없다.
# 어떤 처리를 위해 들어가는 간접적인 시간이나 메모리
성능이 빠르다.
# 처리 속도
# React : 30 ~ 110 MB
# Svelte : 15 ~ 30 MB
반응성이 좋다!
반응성 : 앱 상태의 변화가 DOM에 자동으로 반영되는 현상
데이터가 변수에 "할당"되면, DOM에 반영된다.
데이터와 변수를 연결하는 것 : 바인딩
Svelte는 앱을 바닐라JS로 변환 (컴파일)하고, 그 결과만 동작한다.
Svelte는 브라우저에서 동작하지 않는다.
자유도는 높으나, 호출 스택이나 메모리 참조등, 바닐라JS의 동작 원리를 잘 이해하는 것이 중요하다.
REPL 이란?
사용자에게 데이터를 입력받고 이를 실행하고 결과를 반환하는 단순한 상호작용 컴퓨터 프로그래밍 환경
Svelte 공식 REPL 페이지
Svelte에서 변수 사용하기
<!-- App.svelte -->
<script>
let name = 'world';
</script>
<h1>Hello {name}!</h1>
<button on:click={() => { name = "jinho" }}>
Change!
</button>
<-- 결과물
Hello world!
Change! 버튼 ( 누르면 world 가 jinho로 바뀜 )
-->
Svelte파일 React의 컴포넌트 형식으로 사용하기
1. 컴포넌트 만들기
<!-- Hello.svelte -->
<h2>Bye..</h2>
2. 컴포넌트 불러오기
<!-- App.svelte -->
<script>
<!-- 컴포넌트 불러오기 -->
import Hello from './Hello.svelte';
let name = 'world';
</script>
<h1>Hello {name}!</h1>
<button on:click={() => { name = "jinho" }}>
Change!
</button>
<!-- 컴포넌트 사용하기 -->
<Hello/>
<-- 결과물
Hello world!
Change! 버튼 ( 누르면 world 가 jinho로 바뀜 )
Bye..
-->
간편하게 Svelte 프로젝트 다운받기 ( REPL )
다운받은 프로젝트 폴더에 Svelte 설치하기
// 다운받은 svelte 폴더 안에서 실행
npm install
Node.js 패키지로 Svelte 설치하기
npx degit sveltejs/template <폴더이름>
// degit : git 저장소의 복사본을 만들어, 내 컴퓨터에 다운받는 Node.js 패키지
// sveltejs/template 저장소를 복사해, 지정된 폴더 넣는다.
VsCode Svelte 확장프로그램 설치하기
조건에 따른 클래스 붙이기
<script>
let age = 90
function assign(){
age = 25
}
</script>
<!-- age가 85보다 작으면, active 클래스를 추가한다 -->
<h2 class={age < 85 ? "active" : ""}>
{age}
</h2>
<button on:click={assign}>
Assign
</button>
<style>
/* active 클래스를 가진 요소 파란색 */
.active {
color: blue;
}
</style>
input에서 데이터 받아서, 변수 변경하기
<script>
let name = 'world';
</script>
<h1>{name}</h1>
<-- "bind:"를 사용하면, value에서 받은 데이터를 변수와 연결해준다 -->
<input type="text" bind:value={name}/>
조건문 사용하기 (if)
<script>
let name = 'world'
let toggle = false
</script>
<button on:click={() => {toggle = !toggle}}>
Toggle
</button>
<!-- #if 으로 조건문 시작 -->
{#if toggle}
<h1>Hello {name}!</h1>
<!-- :else 으로 다른 조건 지정 -->
{:else}
<div> No name!</div>
<!-- /if 으로 조건문 끝 -->
{/if}
반복문 사용하기 (each)
<script>
let name = 'world';
let fruits = ['Apple', 'Orange', 'Mango', 'Cherry']
function deleteFruit() {
// 1번째 부터 마지막까지 잘라, 새로운 배열 만들기
fruits = fruits.slice(1)
}
</script>
<h1>Hello {name}!</h1>
<ul>
<!-- #each로 반복문 시작, fruits에서 하나씩 선택해 fruit 변수에 넣어줌 -->
{#each fruits as fruit}
<li>{fruit}</li>
<!-- #each로 반복문 끝 -->
{/each}
</ul>
<button on:click={deleteFruit}>
Eat
</button>
이벤트 추가하기 (onMount 사용)
<script>
// onMount : 컴포넌트가 연결되면 콜백을 실행
import { onMount } from 'svelte'
let name = 'world';
// 스타일을 지정할 때 사용하는 변수
let isRed = false
// 콜백지정, box 클래스를 가진 요소에 click 이벤트를 추가함
onMount(() => {
const box = document.querySelector(".box")
box.addEventListener('click', () => { isRed = !isRed })
})
</script>
<h1>Hello {name}!</h1>
<!-- 배경색을 isRed 조건에 따라 바꾸기 -->
<div class="box" style="background-color: {isRed ? 'red' : 'orange'}">
Box!
</div>
<style>
.box {
width: 300px;
height: 150px;
background-color: orange;
}
</style>
이벤트 추가하기 (function 사용 / 태그에서 지정)
<script>
// import { onMount } from 'svelte'
let name = 'world';
let isRed = false
// onMount(() => {
// const box = document.querySelector(".box")
// box.addEventListener('click', () => { isRed = !isRed })
// })
function enter(){
name = 'enter'
}
function leave(){
name = 'leave'
}
</script>
<h1>Hello {name}!</h1>
<div class="box"
style="background-color: {isRed ? 'red' : 'orange'};"
on:click={() => { isRed = !isRed }}
on:mouseenter={enter}
on:mouseleave={leave}
>Box!</div>
<style>
.box {
width: 300px;
height: 150px;
background-color: orange;
}
</style>
이벤트 추가하기 (bind: 사용)
<script>
let text = '';
</script>
<h1>{text}</h1>
<input type="text"
value={text}
on:input={(e) => {text = e.target.value}}/>
<input type="text"
bind:value={text}/>
<button on:click={() => {text = 'Jinho'}}>
Click
</button>
반복문 사용시, 배열 순서 반대로 적용하기
<script>
let fruits = ['Apple', 'Banana', 'Cherry', 'Orange', 'Mange'];</script>
<h2>Fruits</h2>
<ul>
{#each fruits as fruit}
<li>{fruit}</li>
{/each}
</ul>
<h2>Fruits reverse</h2>
<ul>
<!-- reverse()를 사용해 배열의 순서를 바꾼다 -->
<!-- 원본 배열을 유지하기위해, [...fruits]로 복사본 배열 만들기 -->
{#each [...fruits].reverse() as fruit}
<li>{fruit}</li>
{/each}
</ul>
<h2>Fruits</h2>
<ul>
{#each fruits as fruit}
<li>{fruit}</li>
{/each}
</ul>
컴포넌트로 데이터 주고받기 ( React의 Props )
1. 메인 앱 작성
<!-- App.svelte -->
<script>
// Fruits.svelte 파일 컴포넌트로 불러오기
import Fruits from './Fruits.svelte'
let fruits = ['Apple', 'Banana', 'Cherry', 'Orange', 'Mange'];
</script>
<!-- fruits 배열 Props로 전달하고, 컴포넌트 출력하기 -->
<Fruits {fruits}/>
<Fruits {fruits} reverse/>
<Fruits {fruits} slice='-2'/>
<Fruits {fruits} slice='0,3'/>
2. 컴포넌트 작성
<!-- Fruits.svelte -->
<script>
// Props 받아오기
export let fruits
export let reverse
export let slice
// 인자 확인해서, 각각에 맞는 배열 만들기
let computedFruits = []
let name = ''
// reverse 일시, 배열을 반대로 나열해서 돌려줌
if (reverse) {
computedFruits = [...fruits].reverse()
name = 'reverse'
// slice 일시, 배열을 잘라서 돌려줌
} else if (slice) {
computedFruits = fruits.slice(slice.split(','))
name = `slice ${slice}`
// 기본 배열을 돌려줌
} else {
computedFruits = fruits
}
</script>
// 이름을 알려줌
<h2>Fruits {name}</h2>
<ul>
// Props에 맞는 배열 나타내줌
{#each computedFruits as fruit}
<li>{fruit}</li>
{/each}
</ul>
데이터 스토어 만들기
1. 스토어 만들기
// store.js
// svelte/store 모듈의 writable 함수(스토어에 정보 저장하는 함수)를 불러온다
import { writable } from 'svelte/store'
// writable을 이용해, 스토어에 storeName이란 이름의 변수를 저장한다.
export let storeName = writable('Jinho')
2. 메인 앱 작성
<!-- App.svelte -->
<script>
// 아까 만든 스토어를 불러온다
import { storeName } from './store.js'
// 부모 컴포넌트 연결
import Parent from './Parent.svelte'
let name = 'world';
// $storeName : 자동 구독 auto-subscription - 스토어에서 자동으로 변수를 가져와준다.
$storeName = name
</script>
<h1>
Hello {name}!
</h1>
// 부모 컴포넌트 출력
<Parent name={name}/>
3. 부모 컴포넌트 작성
<script>
import Child from './Child.svelte'
</script>
<div>
Parent
</div>
<Child/>
4. 자식 컴포넌트 작성
<script>
import { storeName } from './store.js'
</script>
<div>
<!-- 스토어에서 자동으로 변수 가져오기 -->
Child {$storeName}
</div>
스토어가 필요한 이유
프로그램을 작성하면서 변수가 많아지고, 기존의 방법으로(export) 많은 컴포넌트끼리 연결하다 보면
변수가 복잡하게 연결되어 있어, 어디서 어떻게 연결되어있는지 알아보기 힘들어진다.
이를 방지하기 위해, 모든 변수들을 가지고 있는 스토어 파일을 만들어 변수들을 보기쉽고 편하게 관리할 수 있다.
반응형