ทำ cross-component reactive states ด้วย Runes ใน Svelte 5
หลังจากที่ 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
- เราจะกำหนด 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 กันได้ง่ายมากขึ้น