禁用严格模式后useFetch仍调用两次且子组件重复渲染问题
问题解答
一、useFetch被调用两次的原因
- 自定义Hook的执行时机和组件渲染强绑定:组件每次渲染时,其函数体内的所有Hook都会同步执行一遍。
- App组件触发了两次渲染:
- 第一次是初始渲染,此时
data的初始值为false,组件执行到useFetch调用时,打印useFetch fires。 - 当
useEffect中的请求完成后,调用setData更新data状态,触发App组件二次渲染,此时useFetch会再次执行,所以你看到该日志打印两次。
- 第一次是初始渲染,此时
- 而
useEffect的依赖项为空数组,只会在组件初始挂载阶段执行一次,因此useEffect fires仅打印一次,这完全符合React的Hook执行规则。
二、阻止return (<Navbar />)
这类子组件重复渲染的方案
return (<Navbar />)最直接有效的方式是用React.memo包裹Navbar组件,它会对组件的props做浅比较,只有当props发生变化时才会触发重新渲染:
修改Navbar组件示例:
import { memo } from 'react'; const Navbar = memo(() => { // Navbar原有业务代码 return ( // Navbar的JSX结构 ); }); export default Navbar;
额外优化建议
你的useFetch直接依赖外部的setData,不符合Hook的封装原则,建议把状态管理内置到Hook中,让职责更清晰:
// 修改后的useFetch.js import { useState, useEffect } from 'react'; export default function useFetch(path) { const [data, setData] = useState(false); const [error, setError] = useState(null); console.log('useFetch fires'); useEffect(() => { console.log('useEffect fires'); const fetchData = async () => { try { const response = await fetch(path); const newData = await response.json(); setData(newData); } catch (err) { setError('something went wrong!'); } }; fetchData(); }, [path]); return { data, error }; } // 修改后的App.js function App() { const { data, error } = useFetch('/api/path'); return ( <div className="App"> <header className="App-header"> <Navbar /> <img src={logo} className="App-logo" alt="logo" /> </header> <div> {error && error} {data ? <Data data={data} /> : 'LOADING...'} </div> </div> ); }
内容的提问来源于stack exchange,提问作者docHoliday
相关产品推荐
相关产品推荐

