Sending Http Requests feat. Star Wars API
本文使用 Star Wars API 為例示範 React 如何串接第三方 API。
範例:串接 Star Wars API
- API: Application Programming Interface
- SWAPI Film List
- Package axios
- Built-in Fetch API
- HTTP response status codes
使用 Fetch 透過網路取得 JSON,回傳的 response 需要先透過 json()
轉換,然後我們就能開始使用資料!
這邊有個小細節就是使用 map()
篩選出我們需要的欄位,不要把整包 API 資料都帶走,減少資料的複雜度。
1function fetchMovieHandler() { 2 fetch('https://swapi.dev/api/films') 3 .then((res) => { 4 return res.json(); 5 }) 6 .then((data) => { 7 const transformedMovies = data.results.map((movieData) => { 8 return { 9 id: movieData.episode_id, 10 title: movieData.title, 11 openingText: movieData.opening_crawl, 12 releaseDate: movieData.release_date, 13 }; 14 }); 15 setMovies(transformedMovies); 16 }) 17 .catch((err) => { 18 console.log(err); 19 }); 20} 21
我們也可以搭配 Async/Await 來使用,我本身也比較喜歡 async/await
大於 .then()
,因為讀起來更簡單、直覺。
注意,使用時除了在 Fetch 加上 await
之外,使用 json()
把回傳結果的 body text 解析成 JSON 型別的時候也要加上 await
。
1async function fetchMovieHandler() { 2 const response = await fetch('https://swapi.dev/api/films'); 3 const data = await response.json(); 4 5 const transformedMovies = data.results.map((movieData) => { 6 return { 7 id: movieData.episode_id, 8 title: movieData.title, 9 openingText: movieData.opening_crawl, 10 releaseDate: movieData.release_date, 11 }; 12 }); 13 setMovies(transformedMovies); 14} 15
Loading & Error Handling
最後是加上 Loading 與錯誤處理的部分,我們會用 Fetch API 作為範例,如果用的是其他 API 像是 axios,可能在寫法上會有些許差異。
1function App() { 2 const [movies, setMovies] = useState([]); 3 const [isLoading, setIsLoading] = useState(false); // 是否正在讀取 4 const [error, setError] = useState(null); // 錯誤訊息 5 6 async function fetchMovieHandler() { 7 setIsLoading(true); 8 setError(null); 9 10 // 使用 try...catch 處理錯誤 11 try { 12 const response = await fetch('https://swapi.dev/api/films'); 13 // 檢查 Fetch 回傳的狀態 14 if (!response.ok) { 15 throw new Error('Something went wrong!'); 16 } 17 const data = await response.json(); 18 const transformedMovies = data.results.map((movieData) => { 19 return { 20 id: movieData.episode_id, 21 title: movieData.title, 22 openingText: movieData.opening_crawl, 23 releaseDate: movieData.release_date, 24 }; 25 }); 26 setMovies(transformedMovies); 27 } catch (error) { 28 setError(error.message); 29 } 30 31 // 不論成功失敗最後都會關閉讀取 32 setIsLoading(false); 33 } 34 35 // 處理不同狀態下的呈現內容 36 let content = <p>Found no movies.</p>; 37 if (movies.length > 0) { 38 content = <MoviesList movies={movies} />; 39 } 40 if (error) { 41 content = <p>{error}</p>; 42 } 43 if (isLoading) { 44 content = <p>Loading...</p>; 45 } 46 47 return ( 48 <React.Fragment> 49 <section> 50 <button onClick={fetchMovieHandler}>Fetch Movies</button> 51 </section> 52 <section> 53 {/* {!isLoading && movies.length > 0 && <MoviesList movies={movies} />} 54 {!isLoading && movies.length === 0 && !error && <p>Found no movies.</p>} 55 {isLoading && <p>Loading...</p>} 56 {!isLoading && error && <p>{error}</p>} */} 57 {content} 58 </section> 59 </React.Fragment> 60 ); 61} 62 63export default App; 64
Working with useEffect and useCallback Hooks
最後我們用 useEffect 讓畫面渲染後先 Call API 獲取一次資料。
除此之外,我們會加上 useCallback 確保 fetchMovieHandler
函式不會在 useEffect 中形成無限迴圈,因此要在 dependency array 放入函式內有使用到的狀態。
(在這個範例中我們沒有使用任何依賴,但其他情況下就有可能會用到)
1const fetchMovieHandler = useCallback(async () => { 2 // Do the same thing... 3}, []); 4 5useEffect(() => { 6 fetchMovieHandler(); 7}, [fetchMovieHandler]); 8
Sending a POST request to Firebase Realtime Database
Fetch API 除了 GET 之外也能用 POST,寫法是在 fetch()
的第二個參數放一個物件,然後基本上會設定 method
、body
,與 headers
這幾個基本的欄位。
1async function addMovieHandler(movie) { 2 setError(null); 3 4 try { 5 console.log(movie); 6 const response = await fetch( 7 'https://react-http-14f5a-default-rtdb.firebaseio.com/movies.json', 8 { 9 method: 'POST', 10 body: JSON.stringify(movie), // body want JSON data 11 // Firebase 不用設定 Content-Type,但一般保險起見還是都會設定 12 headers: { 13 'Content-Type': 'application/json', 14 }, 15 } 16 ); 17 const data = await response.json(); 18 console.log(data); 19 20 fetchMoviesHandler(); // Fetch movies after adding new movie 21 } catch (error) { 22 setError(error.message); 23 } 24} 25
回顧
看完這篇文章,我們到底有什麼收穫呢?藉由本文可以理解到…
- Fetching API data with useEffect and useCallback Hooks