วิธีการดึงข้อมูล API (Data Fetching) ด้วย Svelte

Svelte Sep 17, 2023

ตัวอย่างนี้ จะพูดถึงแค่วิธีการดึงข้อมูลจาก API ด้วยการใช้ Svelte ธรรมดานะครับ ไม่รวมถึง SvelteKit ซึ่งจะแยกเป็นอีกบทความนึงนะครับ การดึงข้อมูลจาก API ใน Svelte หลักๆ แล้วเนี่ย มี 2 แบบ คือ

  1. ดึงข้อมูลตอน Component Mount ด้วย onMount
  2. ใช้ Await Block {{await}}

ซึ่งสำหรับตัว fetch เราก็จะใช้ fetch ธรรมดาเลย หรือใครจะใช้ axios ก็ได้เช่นกันครับ


แบบที่ 1 - ใช้ onMount

โดยปกติ ทุกๆ component จะมี lifecycle ของมัน เริ่มจากตั้งแต่ created ไปจนถึง destroy โดยที่หนึ่งใน lifecycle ที่สำคัญและมีประโยชน์มากก็คือ onMount

onMount จะรันหลังจากที่ component มัน render DOM เรียบร้อยแล้ว (first rendered to the DOM)

ทีนี้ เมื่อ DOM มัน render เรียบร้อยแล้ว เราก็ call api ที่ตรงส่วนนี้แหละ เพื่อนำค่า มา render ใน Markup

ตัวอย่าง onMount มี syntax แบบนี้

<script>
  import { onMount } from 'svelte'

  onMount(() => {
    // call data
  })
</script>

ตัวอย่าง การดึงข้อมูล API โดยผมใช้ตัวอย่างจากเว็บ {JSON} Placeholder

มี function หลักๆ คือ getPosts เพื่อทำการ fetch data

	async function getPosts() {
		const res = await fetch('https://jsonplaceholder.typicode.com/posts')
		const users = await res.json()

		if (res.ok) {
			return users
		} else {
			throw new Error('Something went wrong!')
		}
	}

ในส่วน onMount ก็เพียงแค่ call function แบบนี้

<script>
	import { onMount } from 'svelte'

	let posts

	onMount(async () => {
		posts = await getPosts()
	})
</script>

และส่วน Markup ก็เพียงแค่ วนลูปด้วย {{#each }} blocks

{#if posts}
	{#each posts as post}
		<article>
			<h1>{post.title}</h1>
			<p>{post.body}</p>
		</article>
	{/each}
{/if}

สุดท้าย ตัวอย่างไฟล์ ในการ fetch api ด้วยการใช้ onMount

<script>
	import { onMount } from 'svelte'

	let posts

	onMount(async () => {
		// 2️⃣ : getPosts จะถูกเรียก ตอน onMount มาเก็บไว้ที่ตัวแปร posts
		posts = await getPosts()
	})

  // 1️⃣ : สร้าง function `getPosts` สำหรับดึงข้อมูล (return เป็น Promise)
	async function getPosts() {
		const res = await fetch('https://jsonplaceholder.typicode.com/posts')
		const users = await res.json()

		if (res.ok) {
			return users
		} else {
			throw new Error('Something went wrong!')
		}
	}

  // 3️⃣ : เราสามารถ fetch data ได้อีกวิธีด้วยการ กด button
  // เพื่อให้ button on:click มาเรียก function นี้
	async function handleClick() {
		posts = await getPosts();
	}
</script>

<button on:click={handleClick}> Fetch Posts </button>

<!-- 4️⃣ : render posts  -->
{#if posts}
	{#each posts as post}
		<article>
			<h1>{post.title}</h1>
			<p>{post.body}</p>
		</article>
	{/each}
{/if}

ตัวอย่าง REPL : https://svelte.dev/repl/8305d4d83b184bafa6b96d30e35f3a62?version=4.2.0

แบบที่ 2 - แบบ Await Block

ตัวอย่างนี้ คือ เราจะสร้าง function ในการดึงข้อมูล api แล้วเก็บเป็น promise ไว้ที่ส่วน <script> จากนั้น ส่วน Markup เราจะใช้ tag {#await}

ตัวอย่าง syntax คือ

{#await expression}...{:then name}...{/await}

ตัวอย่างการใช้งาน

{#await promise}
	<!-- promise is pending -->
	<p>waiting for the promise to resolve...</p>
{:then value}
	<!-- promise was fulfilled -->
	<p>The value is {value}</p>
{:catch error}
	<!-- promise was rejected -->
	<p>Something went wrong: {error.message}</p>
{/await}
Await blocks • Svelte Tutorial
Learn Svelte and SvelteKit with an interactive browser-based tutorial

ตัวอย่าง Await blocks

นำมาเขียนเป็นการ fetch api ด้วย await blocks จะได้แบบนี้

<script>
  // 2️⃣ : Promise ถูกเก็บไว้ที่ตัวแปร `promise`
	let promise = getPosts();

  // 1️⃣ : สร้าง function `getPosts` สำหรับดึงข้อมูล (return เป็น Promise)
	async function getPosts() {
		const res = await fetch('https://jsonplaceholder.typicode.com/posts')
		const users = await res.json()

		if (res.ok) {
			return users
		} else {
			throw new Error('Something went wrong!')
		}
	}

  // 3️⃣ : เราสามารถ fetch data ได้อีกวิธีด้วยการ กด button
  // เพื่อให้ button on:click มาเรียก function นี้
	function handleClick() {
		promise = getPosts();
	}
</script>

<button on:click={handleClick}> Fetch Posts </button>

<!-- 4️⃣ : ส่วนของ await blocks  -->
{#await promise}
	<p>fetching...</p>
{:then posts}
	{#each posts as post}
		<article>
			<h1>{post.title}</h1>
			<p>{post.body}</p>
		</article>
	{/each}
{:catch error}
	<p style="color: red">{error.message}</p>
{/await}

ดูตัวอย่าง REPL ได้ที่นี่ : https://svelte.dev/repl/4da8aa2f60f54e91ae7934c42979656a?version=4.2.0

สรุป

ทั้งสองวิธี ก็เป็นตัวอย่าง แบบง่ายๆ ในการดึงข้อมูล API นะครับ แบบแรก onMount เราอาจจะต้องทำการดัก error เอง รวมถึงสามารถเพิ่ม state fetching ได้เช่นกัน ในขณะที่ส่วน await blocks คือข้อดี เราสามารถจัดการผ่าน markup ได้เลย

นอกจากนี้ เรายังสามารถใช้ร่วมกันได้นะ คือใช้ onMount เพื่อ fetch ข้อมูล (return Promise) และใช้ await block จัดการ state ก็ได้ส่วน markup

เลือกใช้วิธีไหน ก็ลองดูความถนัด หรือตามสถานการณ์กันดูนะครับ

Happy Coding ❤️

Tags

Chai Phonbopit

เป็น Web Dev ทำงานมา 10 ปีหน่อยๆ ด้วยภาษา JavaScript, Node.js, React, Vue และปัจจุบันกำลังสนใจ Web3, Crypto และ Blockchain เขียนบล็อกที่ https://devahoy.com