使用Axios在React中请求数据的方法详解
作者:Supersist
本文主要有以下内容:
- 使用
axios
进行简单的数据获取- 加入状态变量,优化交互体验
- 自定义
hook
进行数据获取- 使用
useReducer
改造请求
重点主要在134点! 本文主要适合于刚接触React的初学者以及不知道如何规范的在React
中获取数据的人。
前置条件:首先准备一个后端接口,其代码如下:
@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
进行环境搭建!在成功搭建环境后,删除掉App.jsx
中的无关代码,删除后的代码如下:
import { useState } from 'react' import './App.css' import axios from 'axios' function App() { return ( <> <div> </div> </> ) } export default App
使用axios进行简单的数据获取
首先修改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
进行数据获取,在这一步需要注意如下:
useEffect()
中的箭头函数不能被async
修饰。useEffect()
的第二个参数的问题
首先是第一点,在app.jsx
中添加如下代码
useEffect(async () => { const result = await axios("http://127.0.0.1:8080/student/list.do") setData(result.data) })
此时项目不能够正常运行,项目会出现如下的报错信息:
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
因此根据错误信息,需要修改我们的写法如下:
useEffect(() => { const fetchData = async () => { const result = await axios("http://127.0.0.1:8080/student/list.do") setData(result.data) } fetchData(); })
这样修改之后,项目可以正常运行了!页面可以正常显示数据了!但是细心的你一定发现了如下问题:stuName
一直在变化。这是因为在使用useEffect
进行数据获取时,如果没有指定第二个参数,即他的依赖,则useEffect
在每一次render都会运行,因此就导致了useEffect
的无限循环。
所以此时我们添加第二个参数即可,代码如下。
useEffect(() => { const fetchData = async () => { const result = await axios("http://127.0.0.1:8080/student/list.do") setData(result.data) } fetchData(); },[])
传递空数组表示,没有任何依赖,即在mounted
后将不会触发该方法。
如果说当我们需要依赖某个参数时,即某个参数发生改变后,我们需要重新加载数据,此时结合后端接口中的参数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>
此时当我们在输入框输入数字时,就会发现内容的改变。但是这样存在了其他问题,每当我们输入一个数时,一位数效果不明显,在输入3位数或者4位数时,每输入一个字符,他都会发出一个http请求。进行数据获取,显然这不是我们要的效果。因此就可以改为手动触发,代码如下:
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> </> ) }
这样就可以通过手动点击查询的方式触发!但这种方式还有可以优化的地方,query
和size
这两个状态变量都用于触发查询功能,且query
就是size
的一个复制,因此可以简化为如下:
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> </> ) }
到这一步简单的数据请求就结束了!如果只是为了获取数据,则到此就结束了!
加入状态变量,优化数据加载过程
写过vue的都应该了解过在element-plus
中的table
组件都有一个loading
配置项,当进行数据请求时,用于显示当前的数据获取状态。这一部分实现的效果就是如此!
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>数据加载中...</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(); }
重新启动项目之后,在这之后的每一次请求页面就会显示一个数据的加载过程!
除了显示数据的加载过程,我们还可以添加异常处理:代码如下,省略了其他没有改变的代码!
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>数据加载出错: {errorInfo.message}</div>) }
自定义hook进行数据获取
在上面的代码中,我们都是将所有的代码写在了同一个jsx
文件里面,这样不利于我们进行代码维护【想象一下有很多很多的状态变量,这个文件得多大!】;因此需要将数据请求的逻辑提取出来放入至新建的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>数据加载出错: {errorInfo.message}</div>) } { isLoading ? (<div>数据加载中...</div>) : ( <ul> { data.data.map(student => { return ( <li key={student.stuId}> {student.stuName} </li> ) }) } </ul> ) } </div> </> ) }
这样前后一对比,就简化了很多很多。即使后面有再多的数据接口按照这种方式,这个文件的内容也不会太多!到这里基本上就可以结束了!不过我们还可以使用useReducer
进一步优化我们的请求!
使用useReducer优化
在上面的代码中errorInfo,isLoading
他们是相关的,但是却是分别维护的,因此为了让其聚合在一起可采用reducer进行优化:
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中请求数据的方法详解的详细内容,更多关于Axios在React中请求数据的资料请关注脚本之家其它相关文章!