使用Axios在React中請求數(shù)據(jù)的方法詳解
本文主要有以下內(nèi)容:
- 使用
axios
進行簡單的數(shù)據(jù)獲取- 加入狀態(tài)變量,優(yōu)化交互體驗
- 自定義
hook
進行數(shù)據(jù)獲取- 使用
useReducer
改造請求
重點主要在134點! 本文主要適合于剛接觸React的初學者以及不知道如何規(guī)范的在React
中獲取數(shù)據(jù)的人。
前置條件:首先準備一個后端接口,其代碼如下:
@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
進行環(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進行簡單的數(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
進行數(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ù)了!但是細心的你一定發(fā)現(xiàn)了如下問題:stuName
一直在變化。這是因為在使用useEffect
進行數(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ā)該方法。
如果說當我們需要依賴某個參數(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>
此時當我們在輸入框輸入數(shù)字時,就會發(fā)現(xiàn)內(nèi)容的改變。但是這樣存在了其他問題,每當我們輸入一個數(shù)時,一位數(shù)效果不明顯,在輸入3位數(shù)或者4位數(shù)時,每輸入一個字符,他都會發(fā)出一個http請求。進行數(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
配置項,當進行數(shù)據(jù)請求時,用于顯示當前的數(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進行數(shù)據(jù)獲取
在上面的代碼中,我們都是將所有的代碼寫在了同一個jsx
文件里面,這樣不利于我們進行代碼維護【想象一下有很多很多的狀態(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
進一步優(yōu)化我們的請求!
使用useReducer優(yōu)化
在上面的代碼中errorInfo,isLoading
他們是相關(guān)的,但是卻是分別維護的,因此為了讓其聚合在一起可采用reducer進行優(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ù)的方法詳解的詳細內(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-07antd中form表單的wrapperCol和labelCol問題詳解
最近學習中遇到了些問題,所以給大家總結(jié),下面這篇文章主要給大家介紹了關(guān)于antd中form表單的wrapperCol和labelCol問題的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-02-02