跳至主要内容

串接 API 入門:用 fetch 把後端資料顯示在畫面上

這是「接下來可以學什麼」系列的第四篇。學會這篇之後,你的 App 就能不再只是顯示假資料,而是能真正抓取網路上的資料來顯示。


一、為什麼需要學「串接 API」?

到目前為止,前面幾篇範例的資料都是直接寫在程式碼裡的「假資料」(例如固定的貼文列表)。但真實世界的 App,資料通常存在後端伺服器上,App 需要透過網路去「要資料」,這個過程就叫做串接 API

簡單比喻:API 就像是「點餐窗口」。

  • App(你)走到窗口,說「我要某某資料」(發送請求)。
  • 後端伺服器(廚房)準備好資料,透過窗口交給你(回傳資料)。
  • 你拿到資料後,把它顯示在畫面上。

二、fetch:最基本的發送請求工具

React Native 內建了 fetch 函式,不用額外安裝套件就能直接使用,這是最基礎、最常見的串接 API 方式。

最簡單的範例

fetch('https://example.com/api/posts')
.then((response) => response.json())
.then((data) => {
console.log(data);
});

拆解一下這段在做什麼:

  1. fetch('網址'):發送一個請求到這個網址。
  2. .then((response) => response.json()):拿到回應後,把它轉換成 JavaScript 可以讀懂的格式(JSON)。
  3. .then((data) => { ... }):拿到轉換後的資料,可以開始使用它。

async / await 寫法(比較好讀,現在更常用)

async function getPosts() {
const response = await fetch('https://example.com/api/posts');
const data = await response.json();
console.log(data);
}

這兩種寫法(.then()async/await)做的事情一樣,只是寫法不同。新手建議直接習慣用 async/await,因為程式碼讀起來會比較像「一步一步往下做」,比較直覺。


三、把 API 資料跟畫面接起來:複習 useState + useEffect

光是抓到資料還不夠,還要把資料存到 State,這樣資料一變化,畫面才會自動更新。這時候就會用到第一篇學過的 useStateuseEffect

import { useState, useEffect } from 'react';
import { View, Text, FlatList } from 'react-native';

export default function PostList() {
const [posts, setPosts] = useState([]); // 用來存放抓到的資料

useEffect(() => {
async function getPosts() {
const response = await fetch('https://example.com/api/posts');
const data = await response.json();
setPosts(data); // 抓到資料後,存進 State
}

getPosts();
}, []); // 空陣列代表:畫面第一次出現時,執行一次就好

return (
<FlatList
data={posts}
keyExtractor={(item) => String(item.id)}
renderItem={({ item }) => (
<View style={{ padding: 16 }}>
<Text>{item.title}</Text>
</View>
)}
/>
);
}

這段程式碼發生的事情:

  1. 畫面第一次出現 → useEffect 執行 → 呼叫 getPosts() 去抓資料。
  2. 抓到資料後,用 setPosts(data) 存進 State。
  3. State 一改變,畫面自動重新渲染,FlatList 就會把抓到的資料顯示出來。

四、補上「載入中」和「錯誤處理」,做出更完整的體驗

實際開發時,網路請求不會總是立刻成功,可能需要等個一兩秒,也可能會失敗(網路不通、伺服器掛掉、網址打錯)。一個完整的畫面,至少要處理三種狀態:

  1. 載入中(Loading):資料還在抓,先顯示「載入中…」。
  2. 成功(Success):資料抓到了,顯示正常內容。
  3. 失敗(Error):抓資料失敗,顯示錯誤訊息,而不是讓畫面空白或當掉。
import { useState, useEffect } from 'react';
import { View, Text, FlatList, ActivityIndicator } from 'react-native';

export default function PostList() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
async function getPosts() {
try {
const response = await fetch('https://example.com/api/posts');

if (!response.ok) {
throw new Error('伺服器回應錯誤');
}

const data = await response.json();
setPosts(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}

getPosts();
}, []);

if (loading) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator size="large" />
<Text>載入中...</Text>
</View>
);
}

if (error) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>發生錯誤:{error}</Text>
</View>
);
}

return (
<FlatList
data={posts}
keyExtractor={(item) => String(item.id)}
renderItem={({ item }) => (
<View style={{ padding: 16 }}>
<Text>{item.title}</Text>
</View>
)}
/>
);
}

拆解新增的部分

  • loading 這個 State:一開始是 true(代表正在載入),不管成功或失敗,最後都會在 finally 裡設成 false
  • error 這個 State:預設是 null(沒有錯誤),如果請求過程出錯,就把錯誤訊息存進去。
  • try / catch / finally:這是 JavaScript 處理「可能會出錯的程式碼」的標準寫法。
    • try 裡面放正常流程。
    • catch 抓住任何錯誤,存進 error
    • finally 不管成功或失敗都會執行,這裡用來把 loading 關掉。
  • response.ok:用來檢查伺服器是不是真的回應成功(例如沒有回傳 404、500 這種錯誤狀態碼)。

五、發送資料給伺服器:不只是「拿資料」,也能「送資料」

除了抓資料(通常是 GET 請求),有時候你需要把資料送到伺服器,例如使用者填寫表單、發一篇新貼文。這時候要用 POST 請求,並且要告訴伺服器你送的資料格式:

async function createPost(title) {
const response = await fetch('https://example.com/api/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ title }),
});

const data = await response.json();
return data;
}

拆解一下:

  • method: 'POST':告訴伺服器,這是要「新增資料」的請求(預設不寫的話,fetchGET,也就是單純拿資料)。
  • headers:告訴伺服器「我送的資料格式是 JSON」。
  • body:實際要送出去的資料,要用 JSON.stringify() 轉成字串格式才能送出。

六、新手常見錯誤整理

  • ❌ 忘記用 await 等待 fetch 完成,直接拿 response 當作最終資料使用 → 結果拿到的不是你想要的內容。
  • ❌ 沒有處理失敗的情況,網路一斷就整個畫面空白或當掉 → 一定要加上 try / catch.catch()
  • useEffect 裡忘記寫依賴陣列 [] → 變成每次畫面重新渲染就重新抓一次資料,造成不必要的重複請求,甚至無限迴圈。
  • POST 請求忘記設定 headersContent-Type → 伺服器可能讀不懂你送過去的資料格式。
  • ❌ 把網址、API 金鑰直接寫死在程式碼裡到處複製貼上 → 建議統一放在一個設定檔或環境變數管理,之後要換網址或金鑰會比較好維護。

七、小結

  • fetch 是 React Native 內建的請求工具,搭配 async/await 寫法最直覺。
  • 抓到的資料要存進 useState,State 改變畫面才會自動更新,這跟第一篇學的概念是一致的。
  • 一個完整的畫面至少要處理「載入中」「成功」「失敗」三種狀態,使用者體驗才會完整。
  • 不只能「拿資料(GET)」,也能「送資料(POST)」,差別在於 methodheadersbody 的設定。

把這篇範例改成串接一個你自己找到的公開測試 API(網路上有很多免費的測試用 API),實際抓抓看資料、故意把網址打錯體驗一下「失敗畫面」會怎麼顯示,會比單純看文字更有感覺。下一篇,也是這個系列的最後一篇,我們會接著介紹打包上架:認識 EAS Build / EAS Submit,怎麼把 App 送上 App Store 跟 Google Play。