12. Context API

2020. 11. 24. 11:13재주껏 하는 Front-End/Svelte (준비중)

반응형

이번에는 Svelte의 Context API에 대해 알아보자. Context API는 서로 다른 컴포넌트 간의 통신이 필요할 때 사용하기 유용한 기능이다. 일반적으로 컴포넌트 간의 통신은 상위 컴포넌트에서 하위 컴포넌트로 전달하는 Props를 사용한다.

 

하지만 컴포넌트의 깊이가 깊고, 최상위 컴포넌트의 데이터를 최하위 컴포넌트에게 전달해야 한다고 가정해보자. 컴포넌트의 깊이만큼 모든 하위 컴포넌트들이 Props를 정의해야 하는데, 중간의 컴포넌트 입장에서는 필요 없는 Props를 선언하여 불필요한 메모리 공간을 낭비하는 꼴이 된다. 또한 코드의 구조가 복잡해지기 때문에 장기적으로 볼 때는 좋은 구조라고 할 수 없다.

 

이런 경우에 사용하는 것이 바로 Context API다. Context API는 Svelte 내장 메서드인 setContextgetContext를 이용하여 내부 모듈에 데이터나 함수를 저장하는 기능으로 어느 컴포넌트에서든 Svelte 모듈을 Import 하여 사용할 수 있다. 기본적인 사용 방법은 아래와 같다.

 

import { setContext, getContext } from 'svelte'

// 데이터를 저장하는 경우
setContext (key, value)

// 데이터를 불러오는 경우
getContext (key)

 

아래의 예제 코드를 보고 실제로 어떻게 사용하는지 확인해보자.

 

1) App.svelte

<script>
	import Map from './Map.svelte';
	import MapMarker from './MapMarker.svelte';
</script>

<Map lat={37} lon={129} zoom={6}>
	<MapMarker lat={37.6} lon={127} label="서울"/>
</Map>

 

2) Map.svelte

<script>
	import { onMount, setContext } from 'svelte';
	import { mapbox, key } from './mapbox.js';

	setContext(key, {
		getMap: () => map
	});

	export let lat;
	export let lon;
	export let zoom;

	let container;
	let map;

	onMount(() => {
		const link = document.createElement('link');
		link.rel = 'stylesheet';
		link.href = 'https://unpkg.com/mapbox-gl/dist/mapbox-gl.css';

		link.onload = () => {
			map = new mapbox.Map({
				container,
				style: 'mapbox://styles/mapbox/streets-v9',
				center: [lon, lat],
				zoom
			});
		};

		document.head.appendChild(link);

		return () => {
			map.remove();
			link.parentNode.removeChild(link);
		};
	});
</script>

<style>
	div {
		width: 100%;
		height: 100%;
	}
</style>

<div bind:this={container}>
	{#if map}
		<slot></slot>
	{/if}
</div>

 

3) MapMaker.svelte

<script>
	import { getContext } from 'svelte';
	import { mapbox, key } from './mapbox.js';

	const { getMap } = getContext(key);
	const map = getMap();

	export let lat;
	export let lon;
	export let label;

	const popup = new mapbox.Popup({ offset: 25 })
		.setText(label);

	const marker = new mapbox.Marker()
		.setLngLat([lon, lat])
		.setPopup(popup)
		.addTo(map);
</script>

 

4) mapbox.js

import mapbox from 'mapbox-gl';

// https://docs.mapbox.com/help/glossary/access-token/
mapbox.accessToken = MAPBOX_ACCESS_TOKEN;

const key = {};

export { mapbox, key };

 

Map.svelte를 보면 setContext를 이용하여 getMap이라는 메서드를 Svelte 모듈 내부에 저장하는 것을 확인할 수 있다. getMap 메서드는 MapBox에서 생성한 Map 인스턴스를 리턴한다. 참고로, setContext의 첫 번째 파라미터인 Key를 지정할 때는 제약 사항이 없기 때문에 빈 리터럴 객체나 빈 함수도 가능하다. (하지만, 아무 의미도 없는 것을 Key로 설정하는 것은 피해야 한다.)

 

MapMaker.svelte를 보면 getContext를 이용하여 getMap 메서드를 내장 변수에 저장하는 것을 알 수 있다. 이후에 지도에 표시하고자 하는 위치에 Marker 객체를 Map 인스턴스에 추가하여 화면에 출력한다.

 

출력 결과는 아래와 같다.

 

그래도 여기는 East Sea가 위에 있네 ...

 

Context API를 사용할 때 주의 사항은 반드시 컴포넌트의 초기화 시점에 사용해야 한다는 것이다. Context API는 반응형으로 동작하지 않기 때문에, 컴포넌트에서 선언한 메서드나 이벤트 핸들러에서 동작하지 않는다. 만약, 반응형을 원한다면 Context API가 아닌 Store를 사용해야만 한다.

 

오늘은 여기까지이며, 다음에는 Module Context와 Debug에 대해 알아보도록 하겠다.

반응형

'재주껏 하는 Front-End > Svelte (준비중)' 카테고리의 다른 글

14. Motion  (0) 2020.12.01
13. Module Context, Debug  (0) 2020.11.27
11. Special Elements  (0) 2020.11.12
10. Slot  (0) 2020.10.29
9. 스토어  (0) 2020.10.07