使用Axios在React中請(qǐng)求數(shù)據(jù)的方法詳解
本文主要有以下內(nèi)容:
- 使用
axios
進(jìn)行簡(jiǎn)單的數(shù)據(jù)獲取- 加入狀態(tài)變量,優(yōu)化交互體驗(yàn)
- 自定義
hook
進(jìn)行數(shù)據(jù)獲取- 使用
useReducer
改造請(qǐng)求
重點(diǎn)主要在134點(diǎn)! 本文主要適合于剛接觸React的初學(xué)者以及不知道如何規(guī)范的在React
中獲取數(shù)據(jù)的人。
前置條件:首先準(zhǔn)備一個(gè)后端接口,其代碼如下:
@GetMapping("list.do") public Map<String,Object> getListData(Integer size) { ? ?if (Objects.isNull(size)){ ? ? ? ?size = 10; ? } ? ?List<Student> resultList = new ArrayList<>(); ? ?for (int i = 1; i <= size; i++) { ? ? ? ?Student student = new Student(); ? ? ? ?student.setStuId(i); ? ? ? ?student.setAge((int) (Math.random() * 100)); ? ? ? ?student.setStuName(UUID.randomUUID().toString().split("-")[0]); ? ? ? ?resultList.add(student); ? } ? ?Map<String, Object> hashMap = new HashMap<>(); ? ?hashMap.put("data",resultList); ? ?hashMap.put("status",200); ? ?return hashMap; }
前端采用react 18.2 + axios
進(jìn)行環(huán)境搭建!在成功搭建環(huán)境后,刪除掉App.jsx
中的無關(guān)代碼,刪除后的代碼如下:
import { useState } from 'react' import './App.css' import axios from 'axios' ? function App() { ?return ( ? ?<> ? ? ?<div> ? ? ?</div> ? ?</> ) } ? export default App
使用axios進(jìn)行簡(jiǎn)單的數(shù)據(jù)獲取
首先修改App.jsx
代碼如下:
function App() { ?const [data, setData] = useState({ ? ?data: [] }) ?return ( ? ?<> ? ? ?<div> ? ? ? student name ? ? ? ?<ul> ? ? ? ? { ? ? ? ? ? ?data.data.map(student =>{ ? ? ? ? ? ? ?return ( ? ? ? ? ? ? ? ?<li key={student.stuId}> ? ? ? ? ? ? ? ? {student.stuName} ? ? ? ? ? ? ? ?</li> ? ? ? ? ? ? ) ? ? ? ? ? }) ? ? ? ? } ? ? ? ?</ul> ? ? ?</div> ? ?</> ) }
首先是使用useEffect
進(jìn)行數(shù)據(jù)獲取,在這一步需要注意如下:
useEffect()
中的箭頭函數(shù)不能被async
修飾。useEffect()
的第二個(gè)參數(shù)的問題
首先是第一點(diǎn),在app.jsx
中添加如下代碼
useEffect(async () => { ? ?const result = await axios("http://127.0.0.1:8080/student/list.do") ? ?setData(result.data) })
此時(shí)項(xiàng)目不能夠正常運(yùn)行,項(xiàng)目會(huì)出現(xiàn)如下的報(bào)錯(cuò)信息:
react-dom.development.js:86 Warning: useEffect must not return anything besides a function, which is used for clean-up.
It looks like you wrote useEffect(async () => ...) or returned a Promise. Instead, write the async function inside your effect and call it immediately:
useEffect(() => { async function fetchData() { // You can await here const response = await MyAPI.getData(someId); // ... } fetchData(); }, [someId]); // Or [] if effect doesn't need props or state
因此根據(jù)錯(cuò)誤信息,需要修改我們的寫法如下:
useEffect(() => { ? ?const fetchData = async () => { ? ? ? ?const result = await axios("http://127.0.0.1:8080/student/list.do") ? ? ? ?setData(result.data) ? } ? ?fetchData(); })
這樣修改之后,項(xiàng)目可以正常運(yùn)行了!頁面可以正常顯示數(shù)據(jù)了!但是細(xì)心的你一定發(fā)現(xiàn)了如下問題:stuName
一直在變化。這是因?yàn)樵谑褂?code>useEffect進(jìn)行數(shù)據(jù)獲取時(shí),如果沒有指定第二個(gè)參數(shù),即他的依賴,則useEffect
在每一次render都會(huì)運(yùn)行,因此就導(dǎo)致了useEffect
的無限循環(huán)。
所以此時(shí)我們添加第二個(gè)參數(shù)即可,代碼如下。
useEffect(() => { ? ?const fetchData = async () => { ? ? ? ?const result = await axios("http://127.0.0.1:8080/student/list.do") ? ? ? ?setData(result.data) ? } ? ?fetchData(); },[])
傳遞空數(shù)組表示,沒有任何依賴,即在mounted
后將不會(huì)觸發(fā)該方法。
如果說當(dāng)我們需要依賴某個(gè)參數(shù)時(shí),即某個(gè)參數(shù)發(fā)生改變后,我們需要重新加載數(shù)據(jù),此時(shí)結(jié)合后端接口中的參數(shù)size
,在App.jsx
中添加如下代碼:
const [size,setSize] = useState(5) ? useEffect(() => { ? ?const fetchData = async () => { ? ? ? ?const result = await axios(`http://127.0.0.1:8080/student/list.do?size=${size}`) ? ? ? ?setData(result.data) ? } ? ?fetchData(); }, [size]) ? <div> ? ? ?student name ? ? ? ? ?<input ? ? ? ? ? ?type='number' ? ? ? ? ? ?value={size} ? ? ? ? ? ?onChange={event => setSize(event.target.value)} ? ? ? ? ? ?/> <ul> ? ? 省略其他代碼 ? ?</ul> ? </div>
此時(shí)當(dāng)我們?cè)谳斎肟蜉斎霐?shù)字時(shí),就會(huì)發(fā)現(xiàn)內(nèi)容的改變。但是這樣存在了其他問題,每當(dāng)我們輸入一個(gè)數(shù)時(shí),一位數(shù)效果不明顯,在輸入3位數(shù)或者4位數(shù)時(shí),每輸入一個(gè)字符,他都會(huì)發(fā)出一個(gè)http請(qǐng)求。進(jìn)行數(shù)據(jù)獲取,顯然這不是我們要的效果。因此就可以改為手動(dòng)觸發(fā),代碼如下:
function App() { ? ?const [size, setSize] = useState(5) ?const [query, setQuery] = useState('') ?const [data, setData] = useState({ ? ?data: [] }) ? ?useEffect(() => { ? ?const fetchData = async () => { ? ? ?const result = await axios(`http://127.0.0.1:8080/student/list.do?size=${size}`) ? ? ?setData(result.data) ? } ? ?fetchData(); }, [query]) ? ?return ( ? ?<> ? ? ?<div> ? ? ? student name ? ? ? ?<input ? ? ? ? ?type='number' ? ? ? ? ?value={size} ? ? ? ? ?onChange={event => setSize(event.target.value)} ? ? ? ?/> ? ? ? ?<button onClick={() => setQuery(size)} >click me</button> ? ? ? ?<ul> ? ? ? ? { ? ? ? ? ? ?data.data.map(student => { ? ? ? ? ? ? ?return ( ? ? ? ? ? ? ? ?<li key={student.stuId}> ? ? ? ? ? ? ? ? {student.stuName} ? ? ? ? ? ? ? ?</li> ? ? ? ? ? ? ) ? ? ? ? ? }) ? ? ? ? } ? ? ? ?</ul> ? ? ?</div> ? ?</> ) }
這樣就可以通過手動(dòng)點(diǎn)擊查詢的方式觸發(fā)!但這種方式還有可以優(yōu)化的地方,query
和size
這兩個(gè)狀態(tài)變量都用于觸發(fā)查詢功能,且query
就是size
的一個(gè)復(fù)制,因此可以簡(jiǎn)化為如下:
? function App() { ?const [size, setSize] = useState(5) ?const [url,setUrl] = useState('http://127.0.0.1:8080/student/list.do?size=5') ?const [data, setData] = useState({ ? ?data: [] }) ?useEffect(() => { ? ?const fetchData = async () => { ? ? ?const result = await axios(url) ? ? ?setData(result.data) ? } ? ?fetchData(); }, [url]) ?return ( ? ?<> ? ? ?<div> ? ? ? student name ? ? ? ?<input ? ? ? ? ?type='number' ? ? ? ? ?value={size} ? ? ? ? ?onChange={event => setSize(event.target.value)} ? ? ? ?/> ? ? ? ?<button onClick={() => setUrl(`http://127.0.0.1:8080/student/list.do?size=${size}`)} >click me</button> ? ? ? ?<ul> ? ? ? ? { ? ? ? ? ? ?data.data.map(student => { ? ? ? ? ? ? ?return ( ? ? ? ? ? ? ? ?<li key={student.stuId}> ? ? ? ? ? ? ? ? {student.stuName} ? ? ? ? ? ? ? ?</li> ? ? ? ? ? ? ) ? ? ? ? ? }) ? ? ? ? } ? ? ? ?</ul> ? ? ?</div> ? ?</> ) }
到這一步簡(jiǎn)單的數(shù)據(jù)請(qǐng)求就結(jié)束了!如果只是為了獲取數(shù)據(jù),則到此就結(jié)束了!
加入狀態(tài)變量,優(yōu)化數(shù)據(jù)加載過程
寫過vue的都應(yīng)該了解過在element-plus
中的table
組件都有一個(gè)loading
配置項(xiàng),當(dāng)進(jìn)行數(shù)據(jù)請(qǐng)求時(shí),用于顯示當(dāng)前的數(shù)據(jù)獲取狀態(tài)。這一部分實(shí)現(xiàn)的效果就是如此!
const [isLoading, setIsLoading] = useState(false) // 省略沒有改變的其他代碼 useEffect(() => { ? ?const fetchData = async () => { ? ? ? ?setIsLoading(true) ? ? ? ?const result = await axios(url) ? ? ? ?setData(result.data) ? ? ? ?setIsLoading(false) ? } ? ?fetchData(); }, [url]) { ? ?isLoading ? (<div>數(shù)據(jù)加載中...</div>) : ( ? ? ? ?<ul> ? ? ? ? ? { ? ? ? ? ? ? ? ?data.data.map(student => { ? ? ? ? ? ? ? ? ? ?return ( ? ? ? ? ? ? ? ? ? ? ? ?<li key={student.stuId}> ? ? ? ? ? ? ? ? ? ? ? ? ? {student.stuName} ? ? ? ? ? ? ? ? ? ? ? ?</li> ? ? ? ? ? ? ? ? ? ) ? ? ? ? ? ? ? }) ? ? ? ? ? } ? ? ? ?</ul> ? ) }
然后在我們的Java
代碼中添加一個(gè)延時(shí)代碼:
try { ? ?TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { ? ?e.printStackTrace(); }
重新啟動(dòng)項(xiàng)目之后,在這之后的每一次請(qǐng)求頁面就會(huì)顯示一個(gè)數(shù)據(jù)的加載過程!
除了顯示數(shù)據(jù)的加載過程,我們還可以添加異常處理:代碼如下,省略了其他沒有改變的代碼!
const [errorInfo,setErrorInfo] = useState({ ? ?isError:false, ? ?message:'' }) useEffect(() => { ? ?const fetchData = async () => { ? ? ? ?setIsLoading(true) ? ? ? ? ?setErrorInfo({ ? ? ? ? ? ?isError:false, ? ? ? ? ? ?message:"no error", ? ? ? }) ? ? ? ?try { ? ? ? ? ? ?const result = await axios(url) ? ? ? ? ? ?setData(result.data) ? ? ? } catch (error) { ? ? ? ? ? ?setErrorInfo({ ? ? ? ? ? ? ? ?isError:true, ? ? ? ? ? ? ? ?message:error.message ? ? ? ? ? }) ? ? ? } ? ? ? ?setIsLoading(false) ? } ? ?fetchData(); }, [url]) ? { errorInfo.isError && (<div>數(shù)據(jù)加載出錯(cuò): {errorInfo.message}</div>) }
自定義hook進(jìn)行數(shù)據(jù)獲取
在上面的代碼中,我們都是將所有的代碼寫在了同一個(gè)jsx
文件里面,這樣不利于我們進(jìn)行代碼維護(hù)【想象一下有很多很多的狀態(tài)變量,這個(gè)文件得多大!】;因此需要將數(shù)據(jù)請(qǐng)求的邏輯提取出來放入至新建的request.js
文件中,代碼如下所示:
?// request.js import { useEffect, useState } from 'react' import axios from 'axios' export const loadStudentList = (initUrl, initData) => { ? ? ?const [url, setUrl] = useState(initUrl) ? ?const [data, setData] = useState(initData) ? ?const [isLoading, setIsLoading] = useState(false) ? ?const [errorInfo, setErrorInfo] = useState({ ? ? ? ?isError: false, ? ? ? ?message: '' ? }) ? ? ?useEffect(() => { ? ? ? ?const fetchData = async () => { ? ? ? ? ? ?setIsLoading(true) ? ? ? ? ? ?setErrorInfo({ ? ? ? ? ? ? ? ?isError: false, ? ? ? ? ? ? ? ?message: "no error", ? ? ? ? ? }) ? ? ? ? ? ?try { ? ? ? ? ? ? ? ?const result = await axios(url) ? ? ? ? ? ? ? ?setData(result.data) ? ? ? ? ? } catch (error) { ? ? ? ? ? ? ? ?setErrorInfo({ ? ? ? ? ? ? ? ? ? ?isError: true, ? ? ? ? ? ? ? ? ? ?message: error.message ? ? ? ? ? ? ? }) ? ? ? ? ? } ? ? ? ? ? ?setIsLoading(false) ? ? ? } ? ? ? ?fetchData(); ? }, [url]) ? ?return [{ data, isLoading, errorInfo }, setUrl]; } ?
此時(shí)App.jsx
的代碼如下所示:
function App() { ? ?const [size,setSize] = useState(5) ?const [{data,isLoading,errorInfo}, doFetch] = loadStudentList('http://127.0.0.1:8080/student/list.do?size=5',{ ? ?data:[] }) ?return ( ? ?<> ? ? ?<div> ? ? ? student name ? ? ? ?<input ? ? ? ? ?type='number' ? ? ? ? ?value={size} ? ? ? ? ?onChange={event => setSize(event.target.value)} ? ? ? ?/> ? ? ? ?<button onClick={() => doFetch(`http://127.0.0.1:8080/student/list.do?size=${size}`)} >click me</button> ? ? ? ? { errorInfo.isError && (<div>數(shù)據(jù)加載出錯(cuò): {errorInfo.message}</div>) } ? ? ? { ? ? ? ? ?isLoading ? (<div>數(shù)據(jù)加載中...</div>) : ( ? ? ? ? ? ?<ul> ? ? ? ? ? ? { ? ? ? ? ? ? ? ?data.data.map(student => { ? ? ? ? ? ? ? ? ?return ( ? ? ? ? ? ? ? ? ? ?<li key={student.stuId}> ? ? ? ? ? ? ? ? ? ? {student.stuName} ? ? ? ? ? ? ? ? ? ?</li> ? ? ? ? ? ? ? ? ) ? ? ? ? ? ? ? }) ? ? ? ? ? ? } ? ? ? ? ? ?</ul> ? ? ? ? ) ? ? ? } ? ? ?</div> ? ?</> ) }
這樣前后一對(duì)比,就簡(jiǎn)化了很多很多。即使后面有再多的數(shù)據(jù)接口按照這種方式,這個(gè)文件的內(nèi)容也不會(huì)太多!到這里基本上就可以結(jié)束了!不過我們還可以使用useReducer
進(jìn)一步優(yōu)化我們的請(qǐng)求!
使用useReducer優(yōu)化
在上面的代碼中errorInfo,isLoading
他們是相關(guān)的,但是卻是分別維護(hù)的,因此為了讓其聚合在一起可采用reducer進(jìn)行優(yōu)化:
? import { useEffect, useState, useReducer } from 'react' import axios from 'axios' ? const dataFetchReducer = (state, action) => { ? ?switch (action.type) { ? ? ? ?case 'FETCH_INIT': ? ? ? ? ? ?return { ? ? ? ? ? ? ? ?...state, ? ? ? ? ? ? ? ?isLoading: true, ? ? ? ? ? ? ? ?errorInfo: { ? ? ? ? ? ? ? ? ? ?isError:false, ? ? ? ? ? ? ? ? ? ?message:'', ? ? ? ? ? ? ? } ? ? ? ? ? }; ? ? ? ?case 'FETCH_SUCCESS': ? ? ? ? ? ?return { ? ? ? ? ? ? ? ?...state, ? ? ? ? ? ? ? ?isLoading: false, ? ? ? ? ? ? ? ?errorInfo: { ? ? ? ? ? ? ? ? ? ?isError:false, ? ? ? ? ? ? ? ? ? ?message:'', ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ?data: action.payload, ? ? ? ? ? }; ? ? ? ?case 'FETCH_FAILURE': ? ? ? ? ? ?return { ? ? ? ? ? ? ? ?...state, ? ? ? ? ? ? ? ?isLoading: false, ? ? ? ? ? ? ? ?errorInfo: { ? ? ? ? ? ? ? ? ? ?isError:true, ? ? ? ? ? ? ? ? ? ?message:action.payload.message, ? ? ? ? ? ? ? } ? ? ? ? ? }; ? ? ? ?default: ? ? ? ? ? ?throw new Error(); ? } } ? export const loadStudentList = (initUrl, initData) => { ? ?const [url, setUrl] = useState(initUrl) ? ?const [state, dispatch] = useReducer(dataFetchReducer, { ? ? ? ?isLoading: false, ? ? ? ?errorInfo: { ? ? ? ? ? ?isError: false, ? ? ? ? ? ?message: '' ? ? ? }, ? ? ? ?data: initData, ? }); ? ?useEffect(() => { ? ? ? ?const fetchData = async () => { ? ? ? ? ? ?dispatch({ type: 'FETCH_INIT' }); ? ? ? ? ? ?try { ? ? ? ? ? ? ? ?const result = await axios(url) ? ? ? ? ? ? ? ?dispatch({ type: 'FETCH_SUCCESS', payload: result.data }); ? ? ? ? ? } catch (error) { ? ? ? ? ? ? ? ?dispatch({ type: 'FETCH_FAILURE',payload:error }); ? ? ? ? ? } ? ? ? ? ? ?// setIsLoading(false) ? ? ? } ? ? ? ?fetchData(); ? }, [url]) ? ? ?return [state, setUrl] } ?
以上就是使用Axios在React中請(qǐng)求數(shù)據(jù)的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Axios在React中請(qǐng)求數(shù)據(jù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于React實(shí)現(xiàn)一個(gè)todo打勾效果
這篇文章主要為大家詳細(xì)介紹了如何基于React實(shí)現(xiàn)一個(gè)todo打勾效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03react hooks使用Echarts圖表中遇到的情況及相關(guān)配置問題
這篇文章主要介紹了react hooks使用Echarts圖表中遇到的情況及相關(guān)配置問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03在create-react-app中使用css modules的示例代碼
這篇文章主要介紹了在create-react-app中使用css modules的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-07-07react實(shí)現(xiàn)todolist的增刪改查詳解
這篇文章主要為大家介紹了react實(shí)現(xiàn)todolist的增刪改查,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2021-12-12基于react?vant實(shí)現(xiàn)彈窗搜索功能
這篇文章主要為大家詳細(xì)介紹了如何基于react?vant實(shí)現(xiàn)彈窗搜索功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-01-01antd中form表單的wrapperCol和labelCol問題詳解
最近學(xué)習(xí)中遇到了些問題,所以給大家總結(jié),下面這篇文章主要給大家介紹了關(guān)于antd中form表單的wrapperCol和labelCol問題的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02