Svelte Nested component 사용하기

웹페이지를 만들다보면 자주 사용하는 레이아웃 부분은 별도로 모듈화 하여 재사용하고 싶어진다. svelte 에도 독립적인 기능을 하는 컴포넌트를 쉽게 만들 수 있으며, 그 컴포넌트를 사용하여 앱의 구조를 조직화하고 코드를 재사용할 수 있게 된다. svelte document 에서 Nested Components 라는 주제로 설명되어 있으니 참고하자.

이전 포스팅에서 만든 결과를 컴포넌트로 분리해서 다시 구성해보기로 한다. 아래 소스는 변경전 소스이다.

<!-- 변경전 -->
<script>
    let contents = {};
    const cdGender = [ { id : null, name : '-'}, 
        { id : 'M', name : '남' }, 
        { id : 'F', name : '여'}];
</script>

<div class="row">
    <div class="col">
        <div class="mb-2">
            <label for="name" class="form-label">이름</label>
            <input type="text" class="form-control"
                bind:value={contents.name}>
        </div>
        <div class="mb-2">
            <label for="gender" class="form-label">성별</label>
            <select class="form-select" bind:value={contents.gender}>
                {#each cdGender as code, i}
                <option value="{code.id}">{code.name}</option>
                {/each}
            </select>
        </div>
    </div>
</div>

1. 중첩된 컴포넌트 만들기

중첩된 컴포넌트를 먼저 만들건데, 이 컴포넌트는 부모 컴포넌트에서 사용될 자식 컴포넌트이다. 자식 컴포넌트는 독립적으로 재사용 가능한 기능이나 뷰를 정의한다. HTML 입력폼이 길어지면 길어질수록 input 과 select 태그를 많이 쓰게 될텐데, 그 부분을 각각 컴포넌트로 분리해보기로 한다.

input 입력부를 별도의 svelte 파일로 정의한다.

<!-- InputText.svelte -->
<script>
    export let title = "제목";
    export let id;
    export let val;
</script>

<label for="{id}" class="form-label">{title}</label>
<input type="text" class="form-control" 
    id="{id}" name="{id}" bind:value={val} 
    placeholder="" aria-label="">

select 입력란도 별도 svelte 파일로 정의한다.

<!-- Select.svelte -->
<script>
    export let title = "제목";
    export let id;
    export let val;
    export let cdSet;
</script>

<label for="{id}" class="form-label">{title}</label>
<select class="form-select" bind:value={val} 
    id="{id}" name="{id}" aria-label="">
{#each cdSet as code, i}
    <option value="{code.id}">{code.name}</option>
{/each}
</select>

2. Nested Component 를 import 하기

이제 만들어놓은 컴포넌트를 가져와 import 만 해서 기존 소스를 대체하기만 하면된다. 컴포넌트간 값전달시에는 공백으로 구분하여 하나씩 입력하면 된다. bind: 기능을 사용하면 바로바로 객체에 입력된 값을 바인딩할 수 있게 된다. 여기만 넣으면 안되고 Nested 컴포넌트내에도 bind: 로 끝까지 연결해줘야 한다. 소스가 원래도 길지 않았어서 별차이가 없다고 생각할지 모르지만, 코드가 길어질수록 유용할 듯 하다.

<!-- 변경후 -->
<script>
    import InputText from './InputText.svelte'
    import Select from './Select.svelte'

    let contents = {};
    const cdGender = [ { id : null, name : '-'}, 
        { id : 'M', name : '남' }, 
        { id : 'F', name : '여'}];
</script>

<div class="row">
    <div class="col">
        <div class="mb-2">
            <InputText id = "name" title="이름" 
                bind:val={contents.name} />
        </div>
        <div class="mb-2">
            <Select id="gender" cdSet={cdGender} 
                bind:val={contents.gender} />
        </div>
    </div>
</div>
svelte 

더 보면 좋을 글들