React应用中调用自定义函数出现多次console.log输出的原因
问题背景
我在React应用中编写了一个用于请求指定URL并检查状态的函数:
import { useEffect, useState } from 'react'; const fetchStatusCode = (url: string) => { const [data, setData] = useState<string | null>(null); useEffect(() => { const fetchStatus = async () => { const response = await fetch(url); return response.statusText; }; fetchStatus().then((res) => setData(res)); }, []); return data; }; export default fetchStatusCode;
在组件中通过console.log('Status', fetchStatusCode('http://my-site.com/abc/token'));调用该函数后,浏览器控制台先后输出:
Status null Status null Status Ok
请问这是预期行为吗?为何会出现多次console.log输出(前两次为null,第三次为Ok)?
答案
这是完全符合React渲染逻辑的预期行为,具体原因如下:
初始渲染的null输出:组件首次渲染时,调用
fetchStatusCode函数,内部useState初始化data为null,因此第一次控制台输出Status null。此时useEffect还未执行(它是在渲染完成后异步触发的),请求还没发起,返回值自然是初始状态。第二次null输出的原因:如果你的项目开启了React 18的严格模式(StrictMode),开发环境下它会强制组件进行两次渲染,用来检测副作用的潜在问题。这会导致
fetchStatusCode被调用第二次,此时状态还未更新,依然返回null,所以控制台第二次输出Status null——生产环境下不会有这次额外渲染。第三次输出Ok的原因:
useEffect中的异步请求完成后,调用setData(res)更新状态,触发组件重新渲染。此时fetchStatusCode返回更新后的data值Ok,控制台就输出了Status Ok。
另外补充:你写的这个函数属于React自定义Hook,按照规范应该命名为useFetchStatusCode;直接在组件渲染流程中调用console.log会导致每次渲染都执行,所以才会看到多次输出。如果只想在状态变化时打印,建议把console.log放到监听data变化的useEffect中。
内容的提问来源于stack exchange,提问作者meez

