使用Axios在React中請求數(shù)據(jù)的方法詳解
本文主要有以下內(nèi)容:
- 使用
axios進(jìn)行簡單的數(shù)據(jù)獲取- 加入狀態(tài)變量,優(yōu)化交互體驗
- 自定義
hook進(jìn)行數(shù)據(jù)獲取- 使用
useReducer改造請求
重點主要在134點! 本文主要適合于剛接觸React的初學(xué)者以及不知道如何規(guī)范的在React中獲取數(shù)據(jù)的人。
前置條件:首先準(zhǔn)備一個后端接口,其代碼如下:
@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)行簡單的數(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()的第二個參數(shù)的問題
首先是第一點,在app.jsx中添加如下代碼
useEffect(async () => {
? ?const result = await axios("http://127.0.0.1:8080/student/list.do")
? ?setData(result.data)
})此時項目不能夠正常運行,項目會出現(xiàn)如下的報錯信息:
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ù)錯誤信息,需要修改我們的寫法如下:
useEffect(() => {
? ?const fetchData = async () => {
? ? ? ?const result = await axios("http://127.0.0.1:8080/student/list.do")
? ? ? ?setData(result.data)
? }
? ?fetchData();
})這樣修改之后,項目可以正常運行了!頁面可以正常顯示數(shù)據(jù)了!但是細(xì)心的你一定發(fā)現(xiàn)了如下問題:stuName一直在變化。這是因為在使用useEffect進(jìn)行數(shù)據(jù)獲取時,如果沒有指定第二個參數(shù),即他的依賴,則useEffect在每一次render都會運行,因此就導(dǎo)致了useEffect的無限循環(huán)。
所以此時我們添加第二個參數(shù)即可,代碼如下。
useEffect(() => {
? ?const fetchData = async () => {
? ? ? ?const result = await axios("http://127.0.0.1:8080/student/list.do")
? ? ? ?setData(result.data)
? }
? ?fetchData();
},[])傳遞空數(shù)組表示,沒有任何依賴,即在mounted后將不會觸發(fā)該方法。
如果說當(dāng)我們需要依賴某個參數(shù)時,即某個參數(shù)發(fā)生改變后,我們需要重新加載數(shù)據(jù),此時結(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>此時當(dāng)我們在輸入框輸入數(shù)字時,就會發(fā)現(xiàn)內(nèi)容的改變。但是這樣存在了其他問題,每當(dāng)我們輸入一個數(shù)時,一位數(shù)效果不明顯,在輸入3位數(shù)或者4位數(shù)時,每輸入一個字符,他都會發(fā)出一個http請求。進(jìn)行數(shù)據(jù)獲取,顯然這不是我們要的效果。因此就可以改為手動觸發(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>
? ?</>
)
}這樣就可以通過手動點擊查詢的方式觸發(fā)!但這種方式還有可以優(yōu)化的地方,query和size這兩個狀態(tài)變量都用于觸發(fā)查詢功能,且query就是size的一個復(fù)制,因此可以簡化為如下:
?
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>
? ?</>
)
}到這一步簡單的數(shù)據(jù)請求就結(jié)束了!如果只是為了獲取數(shù)據(jù),則到此就結(jié)束了!
加入狀態(tài)變量,優(yōu)化數(shù)據(jù)加載過程
寫過vue的都應(yīng)該了解過在element-plus中的table組件都有一個loading配置項,當(dāng)進(jìn)行數(shù)據(jù)請求時,用于顯示當(dāng)前的數(shù)據(jù)獲取狀態(tài)。這一部分實現(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代碼中添加一個延時代碼:
try {
? ?TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
? ?e.printStackTrace();
}重新啟動項目之后,在這之后的每一次請求頁面就會顯示一個數(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ù)加載出錯: {errorInfo.message}</div>) }自定義hook進(jìn)行數(shù)據(jù)獲取
在上面的代碼中,我們都是將所有的代碼寫在了同一個jsx文件里面,這樣不利于我們進(jìn)行代碼維護(hù)【想象一下有很多很多的狀態(tài)變量,這個文件得多大!】;因此需要將數(shù)據(jù)請求的邏輯提取出來放入至新建的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];
}
?此時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ù)加載出錯: {errorInfo.message}</div>) }
? ? ? {
? ? ? ? ?isLoading ? (<div>數(shù)據(jù)加載中...</div>) : (
? ? ? ? ? ?<ul>
? ? ? ? ? ? {
? ? ? ? ? ? ? ?data.data.map(student => {
? ? ? ? ? ? ? ? ?return (
? ? ? ? ? ? ? ? ? ?<li key={student.stuId}>
? ? ? ? ? ? ? ? ? ? {student.stuName}
? ? ? ? ? ? ? ? ? ?</li>
? ? ? ? ? ? ? ? )
? ? ? ? ? ? ? })
? ? ? ? ? ? }
? ? ? ? ? ?</ul>
? ? ? ? )
? ? ? }
? ? ?</div>
? ?</>
)
}這樣前后一對比,就簡化了很多很多。即使后面有再多的數(shù)據(jù)接口按照這種方式,這個文件的內(nèi)容也不會太多!到這里基本上就可以結(jié)束了!不過我們還可以使用useReducer 進(jìn)一步優(yōu)化我們的請求!
使用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中請求數(shù)據(jù)的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Axios在React中請求數(shù)據(jù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
react hooks使用Echarts圖表中遇到的情況及相關(guān)配置問題
這篇文章主要介紹了react hooks使用Echarts圖表中遇到的情況及相關(guān)配置問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03
在create-react-app中使用css modules的示例代碼
這篇文章主要介紹了在create-react-app中使用css modules的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07
antd中form表單的wrapperCol和labelCol問題詳解
最近學(xué)習(xí)中遇到了些問題,所以給大家總結(jié),下面這篇文章主要給大家介紹了關(guān)于antd中form表單的wrapperCol和labelCol問題的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02

