詳解如何使用React Hooks請求資料並渲染
前言
在日常的開發中,從伺服器端非同步獲取資料並渲染是相當高頻的操作。在以往使用React Class元件的時候,這種操作我們已經很熟悉了,即在Class元件的componentDidMount中通過ajax來獲取資料並setState,觸發元件更新。
隨著Hook的到來,我們可以在一些場景中使用Hook的寫法來替代Class的寫法。但是Hook中沒有setState、componentDidMount等函式,又如何做到從伺服器端非同步獲取資料並渲染呢?本文將會介紹如何使用React的新特性Hook來編寫元件並獲取資料渲染。
資料渲染
先來看一個數據渲染的簡單demo
import React,{ useState } from 'react'; function App() { const [data,setData] = useState({ products: [{ productId: '123',productName: 'macbook' }] }); return ( <ul> {data.products.map(i => ( <li key={i.productId}> {i.productName} </li> ))} </ul> ); } export default App;
在demo中,通過useState建立了一個叫data的內部state,該state中有一個產品列表資料儲存產品資料。App元件通過data中的products來渲染產品列表資料到頁面中。
但現在是寫死的一個數據,如果我們期望從伺服器端獲取資料並渲染,那麼就需要在元件渲染完成時fetch服務端資料,然後通過setData去改變state觸發渲染。我們接下來準備用axios來獲取資料。
import React,{ useState,useEffect } from 'react'; import axios from 'axios'; function App() { const [data,productName: 'macbook' }] }); useEffect(async () => { const result = await axios( 'https://c.com/api/products?date=today',); setData(result.data); }); return ( <ul> {data.products.map(i => ( <li key={i.productId}> {i.productName} </li> ))} </ul> ); } export default App;
程式碼中使用到的useEffect就是hook的其中一種,叫effect hook。useEffect會在每次元件渲染的時候觸發,我們使用它來獲取資料並更新state。但是上面的程式碼是有缺陷的,你發現了嗎?
沒錯,只要你執行一下,你就會發現程式進入了一個死迴圈。因為useEffect不僅在元件didMounts的時候被觸發了,還在didUpdate的時候被觸發了。在useEffect中獲取資料後,通過setDate改變state,觸發元件渲染更新,從而又進入到了useEffect中,無限迴圈下去。這並不是我們想要的結果。我們最初想要的,只是希望在didMounts的時候獲取一次資料而已。所以,這種情況下,我們必須要給useEffect方法的第二個引數傳入一個空[],以使得useEffect中的邏輯只在元件didMounts的時候被執行。
import React,); setData(result.data); },[]); //重點 return ( <ul> {data.products.map(i => ( <li key={i.productId}> {i.productName} </li> ))} </ul> ); } export default App;
雖然看起來這個錯誤比較低階,但確實比較多人在新上手hook時常常犯的問題。
當然,useEffect第二個引數,也可以傳入值。當如果有值的時候,那useEffect會在這些值更新的時候觸發。如果只是個空陣列,則只會在didMounts的時候觸發。
另外,執行這段程式碼,你會看到控制檯警告,Promises and useEffect(async () => ...) are not supported,but you can call an async function inside an effect.。所以如果要使用async,需要修改下寫法。
import React,productName: 'macbook' }] }); useEffect(() => { const fetchData = async()=>{ const result = await axios( 'https://c.com/api/products?date=today',); setData(result.data); } fetchData(); },[]); return ( <ul> {data.products.map(i => ( <li key={i.productId}> {i.productName} </li> ))} </ul> ); } export default App;
體驗優化
一般的應用在某些請求過程的互動設計上,會加上loading來緩解使用者焦慮。那在Hook的寫法中,如何實現呢?下面將會介紹。
import React,productName: 'macbook' }] }); const [isLoading,setIsLoading] = useState(false); useEffect(() => { const fetchData = async()=>{ setIsLoading(true); const result = await axios( 'https://c.com/api/products?date=today',); setData(result.data); setIsLoading(false); } fetchData(); },[]); return ( {isLoading ? ( <div>Loading ...</div> ) : ( <ul> {data.products.map(i => ( <li key={i.productId}> {i.productName} </li> ))} </ul> )}; } export default App;
這裡通過加入一個叫isLoading的state來實現。我們在fetch的開始和結束去改變isLoading的值,來控制return返回的元件內容,從而在請求前顯示Loading元件,在請求後顯示產品列表。
錯誤處理
請求的過程經常會由於各種原因失敗,比如網路、伺服器錯誤等等。所以錯誤處理必不可少的。
import React,setIsLoading] = useState(false); const [isError,setIsError] = useState(false); useEffect(() => { const fetchData = async()=>{ setIsError(false); setIsLoading(true); try{ const result = await axios( 'https://c.com/api/products?date=today',); setData(result.data); }catch(e){ setIsError(true); } setIsLoading(false); } fetchData(); },[]); return ( <div> {isError && <div>出錯了...</div>} {isLoading ? ( <div>Loading ...</div> ) : ( <ul> {data.products.map(i => ( <li key={i.productId}> {i.productName} </li> ))} </ul> )}; </div> } export default App;
當請求出錯時,isError會被設定為true,觸發渲染時,錯誤提示元件就會被渲染出來。這裡的處理比較簡單,在真實場景中,你可以在錯誤處理時加入更復雜的邏輯。isError會在每次hook執行的時候被重置。
最後
讀到這你已經基本學會了如何使用React Hooks獲取資料並渲染元件了。
到此這篇關於如何使用React Hooks請求資料並渲染的文章就介紹到這了,更多相關React Hooks請求資料並渲染內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!