Svelte 기초 02 - Store
Tags: svelte, frontend, 스벨트, 웹프런트
Published: 2022-07-13 05:55:42

이번에는 svelte의 전역상태 관리도구인 store에 대해서 알아보겠습니다. 스토어는 전역으로 사용가능한 상태값 저장소입니다. 앱을 만들다보면 컴포넌트에서 사용되는 상태값이 여러개의 다른 컴포넌트에 영향을 주는 일이 자주 발생합니다.

만약 다음과 같은 컴포넌트 구조의 앱이 있다고 할 때 7번 컴포넌트에서 무언가 값을 변경해 10번에 전달해야 한다면 기존 props를 이용해서 통신을 할 경우 다음과 같은 과정이 필요할 것입니다. 이 과정은 결코 효율적이라고는 할 수 없습니다. 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fnbu7jofshzf6xgd9nzo.png)


이럴경우 스토어를 만들고 모든 컴포넌트가 이 스토어를 바라보게 만들면, 아주 쉽게 컴포넌트간 공유할 수 있는 상태값을 만들고 제어할 수 있습니다. 컴포넌트가 스토어를 바라보게만 한다면 상위 또는 하위 컴포넌트를 거치지 않고 바로 상태값을 변경할 수 있습니다. 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9lki3ee0slti8xosrocb.png)


이 스토어를 만들고 사용하는 방법을 알아보겠습니다. 사용하는 방법은 우선 스토어로 사용할 파일을 만드는 것입니다. 보통 stores.js 라는 파일을 만들고 사용합니다. 그리고 Svetle/store의 writable 모듈을 가져와야 합니다. 여기서 writable은 스토어의 종류중에서 가장 많이 사용되는 기본 형태의 스토어정의 모듈입니다. 그리고 const로 스토어이름을 정의하고 writable로 스토어를 생성하면 됩니다. 이때 초기값을 설정할 수 있습니다. 이렇게 만들어진 스토어는 외부에서 import 불러 사용하면 됩니다. 

그럼 이제부터 간단한 예제를 통해서 이 스토어의 사용방법을 자세히 알아보겠습니다. 

```jsx
import { writable } from 'svelte/store';

export const 스토어이름 = writable(스토어기본값)
```

[ + - 예제앱 ]

이예제는 count라는 스토어를 가지고 + 버튼을 클릭하면 count가 증가되고 , - 버튼을 클릭하면 이 count 값이 감소하는 기능을 가집니다.  그리고 변경된 count값은 화면에 바로 표시됩니다. 

우선 stores.js 라는 파일을 만들고 스토어부터 만들어 보도록 하겠습니다. 스토어를 정의 하기 위해서는 svelte/store에서 writable을 import로 불러와야 합니다 .

`stores.js`
```jsx
import { writable } from 'svelte/store';

export const count = writable(0);
```

이제 이 스토어를 참조할 컴포넌트들을 만들겠습니다. 먼저만들 컴포넌트는 count를 증가시키는 역할을 하는 increment 컴포넌트입니다.  스크립트 영역을 만들고 import를 이용해서 stores.js에서 count를 불러오겠습니다. 여기에 onIncre라는 실제로 count를 증가시키는 역할의 메소드를 만들어 주겠습니다. 

스토어의 값을 변경하는 가장 기본적인 방법은 스토어값을 변경하고 다시 재할당 시키는 것입니다. 그래서 count스토어에 +1을 하고 이값을 다시 count스토어에 할당시키겠습니다. 이때 스토어의 값의 경우 일반적인 상태값과 달리 앞에 꼭 달러($)기호를 사용해야 합니다. 

다음으로 마크업영역에서 button을 만들고, 이 버튼에 on:click이벤트를 작성하고 여기에 onIncre 메소드를 연동해주겠습니다. 

`increment.svelte`
```jsx
<script>
	import { count } from './stores.js';

	const onIncre = () => {
		$count = $count + 1;
	}
</script>

<button on:click={onIncre}>+</button>

```

다음은 count를 감소시키는 역할의 컴포넌트인 decrement 컴포넌트를 만들겠습니다.  이번에도 역시 스크립트 영역에 count스토어를 import 가져오는 것으로 시작하겠습니다. 여기에 onDecre라는 count를 감소하는 역할의 메소드를 만들고 마찬가지고 count 스토어에 -1을 한 후 다시 count에 재할당해주도록 만들겠습니다. 

마크업영역에서도 button을 만들고 여기에 on:click 이벤트에 onDecre 메소드를 연동해 주도록 하겠습니다. 

`decrement.svelte`
```jsx
<script>
	import { count } from './stores.js';

	const onDecre = () => {
		$count = $count - 1;
	}
</script>

<button on:click={onDecre}>-</button>

```

세번째로 만들 컴포넌트는 현재 count값을 표현해 주는 countResult컴포넌트 입니다.  스크립트 영역을 만들고 count컴포넌트를 불러오겠습니다. 

다음으로 마크업여역에서 현재 count를 표시해 주겠습니다. 마크업영역에서 스토어를 사용하기 위해서는 마찬가지로 대괄호 안에 $(달러) 스토어이름 즉 $count라고 하면 됩니다. 이렇게 사용된 스토어의 값의 경우 변경이 되면 바로 변경된 값이 반영됩니다. 

`countResult.svelte`
```jsx
<script>
	import { count } from './stores.js';
</script>

<h1>현재 count는 {$count} 입니다.</h1>
```

이제 App.svelte에 이렇게 만들어진 컴포넌트를 import 불러오고 마크업영역에 각각의 컴포넌트들을 배치하도록 하겠습니다. 

`App.svelte`
```jsx
<script>
  import Increment from './increment.svelte';
  import Decrement from './decrement.svelte';
  import CountResult from './countResult.svelte'
</script>

<CountResult />
<Increment />
<Decrement />

```

이제 앱을 실행해 보도록 하겠습니다.

[ 실행결과로  ]

결과를 보면 + 버튼을 클릭하면 count가 증가하고 - 버튼을 클릭하면 count가 감소하는 것을 볼 수 있습니다. 

이것으로 알 수 있는 것은 스토어의 값을 참조하고 조작하면 해당 스토어를 바라보는 모든 컴포넌트에 동시적으로 스토어의 값이 적용되는 것을 확인할 수 있습니다. 일반적인 props을 이용해서 컴포넌트간 통신을 하는 방법보다 훨씬 편리한 기능입니다.

스토어의 상태값은 이처럼 외부에서 직접 상태값을 조작할 수 도 있지만 스토어 내부에 사용자정의 메소드를 만들어 해당 메소드를 호출하는 방식으로 조작할 수 도 있습니다.

그럼 이제 부터 사용자 정의 메소드를 만들어 스토어를 조작하는 방법을 알아보겠습니다. 

다시 stores.js를 열고 우선 createCount라는 스토어 정의 함수를 만들겠습니다.  그리고 여기에 writable에서 필요한 요소인 subscribe, set, update를 사용할 수 있게 준비하고, 초기값으로 0을 설정합니다. 

참고로 writable 스토어는 다음과 같은 기본 메소드를 가지고 있습니다.

- subscribe: 스토어의 값이 변경되면 자동으로 반영하는 역할을 합니다.
- set: store의 값을 초기화하는 옵션입니다.
- update: set이 전체를 초기화 한다면, update는 값의 일부만 변경시키는 역할을 합니다. 주로 커스텀 메소드를 만들 때 사용되는 기능
- get: 자신 또는 다른 스토어의 값을 가져올 때 사용

이제 사용자 정의 메소드로 count를 증가하는 역할의 increment, 감소하는 역할의 decrement 그리고 초기화 시켜주는 역할을 할 reset을 위한 함수들을 만들어 주겠습니다. 

우선 increment의 경우 update라는 것을 통해서 count스토어 값을 변경하겠습니다. update의 사용방법은 스토어 값을 불러와 조작한 후 조작된 값을 리턴시켜 주는 것으로 수정이 이루어 집니다. 참고로 화살표 함수의 경우 한줄로 사용할 경우 자동으로 리턴이 되게 됩니다. 그래서 count를 받아와 count에  +1을 하고 리턴시켜도록 하겟습니다. 

같은 방법으로 decrement도 작성하겠습니다. 그리고 reset의 경우는 값을 초기화 시켜주는 메소드 이므로 set을 이용해 원하는 값으로 만들어 주면 됩니다 .여기서는 0으로 초기화 시켜 주겠습니다. . 

이렇게 만들어진 사용자 정의 메소드는 return을 시켜 주어야 합니다. 그리고 이 메소드들과 함께 외부에서 사용할 writable의 기본 기능들도 리턴에 포함시켜야 합니다. 이번예제의 경우 스토어값을 변경되면 바로 적용하는 subscribe만을 리턴에 포함시키도록 하겠습니다.

참고로 외부에서 만약 따로 조작이 필요할 경우 set이나 update를 리턴해야 하는 경우도 있을 수 있습니다 

이제 export할 count에 지금 우리가 작성한 createCount()함수를 연결해 주면 되겠습니다. 이제 이 사용자 정의 메소드들을 외부 컴포넌트에서 사용해 보겠습니다. 

`stores.js`
```jsx
import { writable } from 'svelte/store';

function createCount() {
	const { subscribe, set, update } = writable(0);

	// 사용자 정의 메소드
	const increment = () => update(count => count + 1);
	const decrement = () => update(count => count - 1);
	const reset = () => set(0);

	return {
		subscribe,
		increment,
		decrement,
		reset
	};
}

export const count = createCount();

```

increment컴포넌트를 열어주겠습니다. 현재 count를 직접 조작하도록 되어있는 부분을 지우고, 우리가 만든 decrement() 메소드로 변경하겠습니다. 사용방법은 스토어이름에 메소드이름을 사용하면 됩니다. 

`increment.svelte`
```jsx
<script>
	import { count } from './stores.js'

	const onIncre = () => {
		count.increment();
	}
</script>

<button on:click={onIncre}>
	+
</button>

```

같은 방법업으로 decrement컴포넌트도 열고 기존의 스토어 제어부분을 지우고 decrement메소드를 적용하도록 하겠습니다. 

`decrement.svelte`
```jsx
<script>
	import { count } from './stores.js'

	const onDecre = () => {
		count.decrement();
	}
</script>

<button on:click={onDecre}>
	-
</button>

```

이제 결과를 실행시켜 보겠습니다.  작성한 코드가 정상이면 이상없이 작동하는 것을 볼 수 있습니다 .

실행결과는 같지만, 스토어의 값을 외부컴포넌트에서 직접조작하기보다 이런식으로 사용자 정의 메소드를 만들어 사용하는 것이 오류를 줄일 수 있고 재사용도 가능하여 좀 더 효율적일 수 있습니다. 

자 이제 store에 대해서 어느정도 이해가 되었을 것입니다. 그럼 다음시간에 또다른 Svelte의 핵심기능으로 찾아오도록 하겠습니다. 

감사합니다.

---

📺 유튜브 채널: [https://www.youtube.com/channel/UC3cJspjF4TRTyD_RS0azeaw](https://www.youtube.com/channel/UC3cJspjF4TRTyD_RS0azeaw)

✍️ 블로그1: [https://dev.to/freeseamew](https://dev.to/freeseamew)

🖍 블로그2: [https://medium.com/@freeseamew](https://medium.com/@freeseamew)

📖 출판 도서

- 교보문고: [http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9791165921132&orderClick=LEa&Kc=](http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9791165921132&orderClick=LEa&Kc=)
- 알라딘: [https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=286865838](https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=286865838)
- yes24: [http://www.yes24.com/Product/Goods/106212164](http://www.yes24.com/Product/Goods/106212164)

🖥 온강라강 강좌

- GraphQL 완전정복: [https://www.inflearn.com/course/graphql-완전정복?inst=ad1d8573](https://www.inflearn.com/course/graphql-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5?inst=ad1d8573)