React

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > React > Axios在React中请求数据

使用Axios在React中请求数据的方法详解

作者:Supersist

这篇文章主要给大家介绍了初学React,如何规范的在react中请求数据,主要介绍了使用axios进行简单的数据获取,加入状态变量,优化交互体验,自定义hook进行数据获取和使用useReducer改造请求,本文主要适合于刚接触React的初学者以及不知道如何规范的在React中获取数据的人

本文主要有以下内容:

  • 使用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>
    </>
  )
}

这样就可以通过手动点击查询的方式触发!但这种方式还有可以优化的地方,querysize这两个状态变量都用于触发查询功能,且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中请求数据的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文