상속 스토어(derived store)
Svlete에서 지원하는 상속 스토어는 하나 이상의 스토어에서 값을 가져오는 스토어를 의미합니다.
상속 스토어 구현 방법을 설명하기 전에 상속 스토어를 사용하지 않은 소스 코드를 살펴봅시다.
ExampleStore.js 파일에는 읽기 전용인 DataList 스토어와 쓰기 가능인 strValue, numValue 스토어가 존재합니다.
[스토어 - ExampleStore.js]
import {readable, writable} from 'svelte/store'
export const DataList = readable([
{id: 1, name: 'AAAAA', number: 100},
{id: 2, name: 'ABBBB', number: 200},
{id: 3, name: 'ABCCC', number: 300},
{id: 4, name: 'ABCDD', number: 400},
{id: 5, name: 'ABCDE', number: 500},
]);
export const strValue = writable('');
export const numValue = writable(0);
다음 사진처럼 input 태그에 값을 입력하면 strValue 스토어의 값이 변경됩니다. +100 버튼을 클릭하면 numValue 스토어의 값을 100 증가시키고 -100 버튼을 클릭하면 100 감소시킵니다.
그리고 다음 조건을 만족하는 DataList 스토어의 데이터가 화면에 출력됩니다.
- DataList 스토어의 name 프로퍼티가 strValue 스토어의 값을 포함
- DataList 스토어의 number 프로퍼티가 numValue 스토어의 값보다 큼
App.svelte 파일의 script 영역에 ExampleStore.js 파일의 스토어를 불러오고 스토어의 값을 변경하는 이벤트 핸들러 함수를 구현합니다.
[App.svelte - script 영역]
<script>
import { DataList, strValue, numValue } from './ExampleStore.js';
const handleChangeStrValue = (e) => {
strValue.set(e.target.value);
}
const handleChangeNumValue = (param) => {
numValue.update(num => num + param);
}
</script>
HTML 영역에 input 요소를 추가하고 문자열을 입력 후 엔터키를 입력하면 script 영역에 구현된 handleChangeStrValue() 함수를 호출하도록 합니다.
[App.svelte - HTML 영역 1. input 요소]
<div>
<input placeholder="키워드를 입력하세요."
on:change={(e) => handleChangeStrValue(e)}
value={$strValue}/>
</div>
HTML 영역에 numValue 스토어의 값을 화면에 출력하고 button 요소를 추가합니다. button 요소에서 클릭이 발생하면, script 영역에 구현된 handleChangeNumValue() 함수를 호출하도록 합니다.
[App.svelte - HTML 영역 2. button 요소]
<div>
<span>numValue: {$numValue}</span>
<button on:click={() => handleChangeNumValue(100)}>+100</button>
<button on:click={() => handleChangeNumValue(-100)}>-100</button>
</div>
HTML 영역에 svelte의 반복문과 조건문을 사용하여 DataList 스토어의 값을 필터링하는 코드를 작성합니다.
[App.svelte - HTML 영역 3. DataList 스토어 필터]
<div>
{#each $DataList as data}
{#if (data.name.includes($strValue)) && (data.number > $numValue)}
<p>id: {data.id}, name: {data.name}, number: {data.number}</p>
{/if}
{/each}
</div>
다음 소스 코드는 script, HTML, CSS 영역이 취합된 App.svelte 파일입니다.
[컴포넌트 - App.svelte]
<script>
import { DataList, strValue, numValue } from './ExampleStore.js';
const handleChangeStrValue = (e) => {
strValue.set(e.target.value);
}
const handleChangeNumValue = (param) => {
numValue.update(num => num + param);
}
</script>
<div>
<div>
<input placeholder="키워드를 입력하세요."
on:change={(e) => handleChangeStrValue(e)}
value={$strValue}/>
</div>
<div>
<span>numValue: {$numValue}</span>
<button on:click={() => handleChangeNumValue(100)}>+100</button>
<button on:click={() => handleChangeNumValue(-100)}>-100</button>
</div>
<div>
{#each $DataList as data}
{#if (data.name.includes($strValue)) && (data.number > $numValue)}
<p>id: {data.id}, name: {data.name}, number: {data.number}</p>
{/if}
{/each}
</div>
</div>
<style>
div {
text-align: center;
}
</style>
상속 스토어 구현
위에서 설명한 소스 코드는 정상적으로 동작합니다. 하지만, 데이터를 필터링하는 로직을 컴포넌트의 HTML 영역에 구현하는 것은 코드의 가독성을 저하시킵니다.
상속 스토어를 사용한다면, 스토어의 값을 변경하는 복잡한 로직과 스토어의 데이터를 필터링하는 로직을 컴포넌트에서 구현하지 않아도 됩니다.
먼저, 상속 스토어를 구현하기 위해 svelte/store 패키지에 존재하는 derived() 함수를 불러옵니다.
import {derived} from 'svelte/store'
derived() 함수의 첫 번째 인자는 값을 가져오는 스토어입니다. 첫 번째 인자의 타입이 배열이므로 하나의 스토어가 될 수도 있고 여러 개의 스토어가 될 수도 있습니다.
derived() 함수의 두 번째 인자는 함수입니다. 이 함수의 인자는 derived() 함수의 첫 번째 인자가 전달되며, derived() 함수의 첫 번째 인자에 작성된 스토어의 값이 변경될 때마다 dervied() 함수의 두 번째 인자로 전달된 함수가 호출됩니다.
상속 스토어의 반환 값은 derived() 두 번째 인자인 함수의 return 값입니다.
ExampleStore.js에 정의된 상속 스토어 filteredDataList는 strValue, numValue 스토어의 값이 변경될 때마다 호출되며, 필터 된 값을 반환합니다.
[스토어 - ExampleStore.js]
import {derived, readable, writable} from 'svelte/store'
export const DataList = readable([
{id: 1, name: 'AAAAA', number: 100},
{id: 2, name: 'ABBBB', number: 200},
{id: 3, name: 'ABCCC', number: 300},
{id: 4, name: 'ABCDD', number: 400},
{id: 5, name: 'ABCDE', number: 500},
]);
export const strValue = writable('');
export const numValue = writable(0);
// 컴포넌트에서 구현된 필터링 로직을 상속 스토어 filteredDataList로 구현함.
export const filteredDataList = derived(
// 첫 번째 인자: 스토어
[DataList, strValue, numValue],
// 두 번째 인자: 스토어가 변경될 때 실행되는 함수
([$DataList, $strValue, $numValue]) => { // dervied() 함수의 첫 번째 인자와 매핑
return $DataList.filter(data => { // 반환 결과
return ((data.name.includes($strValue)) && (data.number > $numValue))
});
}
);
상속 스토어 filteredDataList에서 스토어 DataList의 데이터를 필터 하므로 App.svelte 컴포넌트에서 스토어 DataList의 데이터를 필터링하는 조건문을 제거합니다. 반복문에서 상속 스토어 filteredDataList를 자동 구독합니다.
[컴포넌트 - App.svelte]
<script>
import { DataList, strValue, numValue, filteredDataList } from './ExampleStore.js';
const handleChangeStrValue = (e) => {
strValue.set(e.target.value);
}
const handleChangeNumValue = (param) => {
numValue.update(num => num + param);
}
</script>
<div>
<div>
<input placeholder="키워드를 입력하세요."
on:change={(e) => handleChangeStrValue(e)}
value={$strValue}/>
</div>
<div>
<span>numValue: {$numValue}</span>
<button on:click={() => handleChangeNumValue(100)}>+100</button>
<button on:click={() => handleChangeNumValue(-100)}>-100</button>
</div>
<div>
{#each $filteredDataList as data}
<p>id: {data.id}, name: {data.name}, number: {data.number}</p>
{/each}
</div>
</div>
<style>
div {
text-align: center;
}
</style>
'Svelte' 카테고리의 다른 글
[Svlete]스토어 데이터 세션 스토리지(sessionStorage)에 저장 (1) | 2022.08.05 |
---|---|
[Svelte]사용자 정의 스토어 구현 방법 (0) | 2022.08.05 |
[Svelte]스토어 구독 방법 (0) | 2022.08.04 |
[Svelte]쓰기 가능 스토어 초기화 및 새로운 값 할당 (0) | 2022.08.04 |
[Svelte]스토어 사용 방법 - 읽기 전용(readable) (0) | 2022.08.03 |
댓글