Svelte setContext and getContext

2023-02-22 15:47 更新

上下文 API 為組件提供了一種機(jī)制,可以在不傳遞數(shù)據(jù)和函數(shù)作為 props 或分派大量事件的情況下相互“交談”。這是一項(xiàng)高級(jí)功能,但很有用。

以使用 Mapbox GL 地圖的示例應(yīng)用程序?yàn)槔N覀兿胧褂?nbsp;<MapMarker> 組件顯示標(biāo)記,但我們不想傳遞對(duì)底層 Mapbox 實(shí)例的引用作為每個(gè)組件的 prop。

上下文 API 有兩部分 — ?setContext? 和 ?getContext?。如果組件調(diào)用 ?setContext(key, context)?,則任何子組件都可以使用 ?const context = getContext(key)? 檢索上下文。

讓我們先設(shè)置上下文。在 ?Map.svelte? 中,從 ?svelte? 導(dǎo)入 ?setContext?,從 ?mapbox.js? 導(dǎo)入 ?key? 并調(diào)用 ?setContext?:

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

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

上下文對(duì)象可以是您喜歡的任何內(nèi)容。與生命周期函數(shù)一樣,?setContext? 和 ?getContext? 必須在組件初始化期間調(diào)用;由于 ?map? 在組件掛載之前不會(huì)創(chuàng)建,因此我們的 context 對(duì)象包含一個(gè) ?getMap? 函數(shù)而不是 ?map? 本身。

在等式的另一邊,在 ?MapMarker.svelte? 中,我們現(xiàn)在可以獲得對(duì) Mapbox 實(shí)例的引用:

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

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

標(biāo)記現(xiàn)在可以將自己添加到地圖中。

更完善的 ?<MapMarker>? 版本也可以處理移除和屬性更改,但我們?cè)谶@里只演示上下文。

Context keys

在 ?mapbox.js? 中你會(huì)看到這一行:

const key = {};

我們可以使用任何東西作為鍵——例如我們可以做 ?setContext('mapbox', ...)? 。使用字符串的缺點(diǎn)是不同的組件庫(kù)可能會(huì)意外地使用同一個(gè)字符串;使用對(duì)象字面量意味著鍵在任何情況下都保證不會(huì)發(fā)生沖突(因?yàn)橐粋€(gè)對(duì)象只對(duì)自身具有引用相等性,即 ?{} !== {}? 而?“x”===“x”?),即使你有跨多個(gè)組件層運(yùn)行的多個(gè)不同上下文。

Contexts vs. stores

Contexts 和 stores 看起來(lái)很相似。它們的不同之處在于,stores 可用于應(yīng)用程序的任何部分,而 context 僅可用于組件及其后代。如果你想使用一個(gè)組件的多個(gè)實(shí)例,而一個(gè)組件的狀態(tài)不會(huì)干擾其他組件的狀態(tài),這會(huì)很有幫助。

事實(shí)上,您可以將兩者結(jié)合使用。由于 context 不是反應(yīng)性的,因此隨時(shí)間變化的值應(yīng)該表示為存儲(chǔ):

const { these, are, stores } = getContext(...);

示例代碼

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

<Map lat={35} lon={-84} zoom={3.5}>
	<MapMarker lat={37.8225} lon={-122.0024} label="Svelte Body Shaping"/>
	<MapMarker lat={33.8981} lon={-118.4169} label="Svelte Barbershop & Essentials"/>
	<MapMarker lat={29.7230} lon={-95.4189} label="Svelte Waxing Studio"/>
	<MapMarker lat={28.3378} lon={-81.3966} label="Svelte 30 Nutritional Consultants"/>
	<MapMarker lat={40.6483} lon={-74.0237} label="Svelte Brands LLC"/>
	<MapMarker lat={40.6986} lon={-74.4100} label="Svelte Medical Systems"/>
</Map>

  • 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.;

		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>

  • MapMarker.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>

  • 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 };


以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)