React组件使用Axios请求时3次渲染是否正常及原因
React组件3次渲染是否正常?原因解析
代码实现
useBaseAxios基础请求钩子
import { useState, useEffect} from 'react'; import axios from 'axios'; const baseAxios = axios.create({ baseURL: "http://127.0.0.1:8000/api/v1", }); const useBaseAxios = ({ method = "GET", url }) => { const [data, setData] = useState(null); const [isLoading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const controller = new AbortController(); const signal = controller.signal; const fetchData = async () => { try { const response = await baseAxios.request({ method, url, signal }) setData(response.data) } catch (error) { if (!axios.isCancel(error)){ setError(error) } } finally { setLoading(false) } } if (!data) { fetchData() } return () => { controller.abort() } }, [method, url]) return [data, isLoading, error] }; export default useBaseAxios;
useClosestLessons业务钩子
import useBaseAxios from "./useBaseAxios"; function useClosestLessons() { const [data, isLoading, error] = useBaseAxios({ method: 'GET', url: '/lessons' }) let lessonsSchedule = []; let currentLesson = {}; if (data) { lessonsSchedule = [...data] currentLesson = lessonsSchedule[0] } return [lessonsSchedule, currentLesson, isLoading, error] } export default useClosestLessons
Main组件
import React from "react"; import './Main.scss'; import useClosestLessons from "../../hooks/fetch-hooks/useClosestLessons"; import { useState, useEffect, useCallback } from "react"; import axios from "axios"; const Main = () => { const [lessonsSchedule, currentLessons, isLoading, error] = useClosestLessons(); console.log(lessonsSchedule) console.log(currentLessons) if (isLoading) return (<p>Загрузка...</p>) return(...)
问题描述
使用上述代码开发React应用,未开启StrictMode,原本预期控制台先输出null、null,随后输出目标数组与对象,但实际显示Main组件发生了3次渲染。请问该现象是否正常?若正常,原因是什么?
回答
这个现象是正常的,三次渲染的触发原因如下:
- 初始挂载渲染:组件首次加载时,
useBaseAxios的data为初始值null,isLoading为true。此时useClosestLessons会返回空数组[]和空对象{},控制台打印这两个值。 - data状态更新触发的渲染:接口请求成功后,执行
setData(response.data)修改data状态,触发组件第二次渲染。这次渲染时,lessonsSchedule和currentLesson会基于接口返回的数据生成对应数组和对象。 - isLoading状态更新触发的渲染:请求完成后进入
finally块,执行setLoading(false)修改加载状态,触发组件第三次渲染。
额外说明两点:
- 你预期的
null输出不会出现,因为useClosestLessons中当data为null时,已经给lessonsSchedule和currentLesson分别赋值了空数组和空对象。 - 之所以会出现两次状态更新触发的渲染,是因为在React 18及之前版本中,异步回调(比如你的
fetchData异步函数)里的状态更新不会被批量处理,setData和setLoading这两个状态更新会分别触发一次渲染,加上初始渲染就形成了三次渲染。
内容的提问来源于stack exchange,提问作者Artem
相关产品推荐
相关产品推荐

