ทำ cross-component reactive states ด้วย Runes ใน Svelte 5

Jakee Indapanya
2 min readNov 21, 2024

หลังจากที่ Svelte 5 ปล่อย runes ออกมา ใน doc เกี่ยวกับ stores ซึ่งเป็นเครื่องมือที่ช่วยให้เราจัดการ state ใน svelte ได้ง่ายมากขึ้น แนะนำให้เราเปลี่ยนไปใช้ runes เพื่อทำ cross-components reactive states ซึ่งเราสามารถใช้ file ประเภทใหม่ .svelte.ts หรือ .svelte.js เพื่อดึง runes มาใช้งานได้คล้ายๆ กับการเขียน composable หรือ react hook

คำถามคือแล้วเราจะเขียนมันยังไงดี?

จริงๆ แล้วการเขียน runes มีหลากหลายวิธีมาก ทั้งการ export $state() ออกไปตรงๆ เลย หรือ export function ที่ update runes ออกไปเช่น

// shareState.svelte.ts
const shareState = $state(false)

export function createShareState() {
get shareState() {
return shareState;
}

set shareState(value: boolean) {
shareState = value;
}

toggle() {
shareState = !shareState;
}
}

แล้วไปเรียกใช้ const shareState = createShareState() เอาใน component ต่างๆ ก็ได้ เป็นวิธีการที่เรียบง่ายดี

แต่สิ่งน่าสนใจกว่านั้นการแชร์ runes ด้วย Context ซึ่งถูกแนะนำเอาไว้ใน doc ว่าเป็นวิธีการที่ปลอดภัยกว่าในการใช้งาน runes แบบ cross-components

  1. เราจะกำหนด class ที่ใช้สร้าง runes ที่เราต้องการจะแชร์
// sidebarState.svelte.ts
class SidebarState {
sidebar = $state<{ show: boolean }>({ show: false });
constructor() { }
toggle() {
return this.sidebar.show = !this.sidebar.show;
}
}

2. ใช้ setContextและ getContext ในการเรียกใช้ class ดังกล่าว

// sidebarState.svelte.ts
import { getContext, setContext } from "svelte";

export class SidebarState {
sidebar = $state<{ show: boolean }>({ show: false });
constructor() { }
toggle() {
return this.sidebar.show = !this.sidebar.show;
}
}

const SIDEBAR_KEY = Symbol('SIDEBAR');

export function setSidebarState() {
return setContext(SIDEBAR_KEY, new SidebarState());
}

export function getSidebarState() {
return getContext<ReturnType<typeof setSidebarState>>(SIDEBAR_KEY);
}

3. เราจะสามารถสร้าง action ที่ componentA โดยแสดงผลที่ componentB ได้

// +page.svelte
<script>
import ComponentA from '$lib/components/componentA.svelte';
import ComponentB from '$lib/components/componentB.svelte';
import { setSidebarState } from '$lib/components/sidebarState.svelte';

setSidebarState();
</script>

<ComponentA />
<ComponentB />
// componentA.svelte
<script>
import { getSidebarState } from './sidebarState.svelte';
const sidebarState = getSidebarState();
</script>

<div>
<button onclick={() => sidebarState.toggle()}>
toggle show sidebar
</button>
</div>
// componentB.svelte
<script>
import { getSidebarState } from './sidebarState.svelte';

const sidebarState = getSidebarState();
</script>

<div>
<p>
{sidebarState.sidebar.show}
</p>
</div>

จาก concept นี้ น่าจะช่วยให้ทุกคนสามารถออกแบบ component ด้วย runes กันได้ง่ายมากขึ้น

--

--

No responses yet