You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

禁用严格模式后useFetch仍调用两次且子组件重复渲染问题

问题解答

一、useFetch被调用两次的原因

  • 自定义Hook的执行时机和组件渲染强绑定:组件每次渲染时,其函数体内的所有Hook都会同步执行一遍。
  • App组件触发了两次渲染:
    1. 第一次是初始渲染,此时data的初始值为false,组件执行到useFetch调用时,打印useFetch fires。
    2. 当useEffect中的请求完成后,调用setData更新data状态,触发App组件二次渲染,此时useFetch会再次执行,所以你看到该日志打印两次。
  • 而useEffect的依赖项为空数组,只会在组件初始挂载阶段执行一次,因此useEffect fires仅打印一次,这完全符合React的Hook执行规则。

二、阻止
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 08:15:14