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

React报错:Rendered fewer hooks than expected 求助排查

问题描述

跟随freecodecamp的YouTube教程编写React代码,教程代码可正常运行,但我的代码出现报错:

Uncaught Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement

原本期望渲染API返回的产品图片,却出现该错误,我的代码如下:

import React, { useEffect, useState } from "react";
import "./style.css";

export default function LoadMoreImages() {
  const [products, setProducts] = useState([]);
  const [count, setCount] = useState(0);
  const [loading, setLoading] = useState(false);
  const [disableButton, setDisableButton] = useState(false);

  async function fetchingProducts() {
    try {
      setLoading(true);
      const response = await fetch(
        `https://dummyjson.com/products?limit=20&skip=${
          count === 0 ? 0 : count * 20
        }`
      );
      const result = await response.json();

      if (result && result.products && result.products.length) {
        setProducts((prevData) => [...prevData, ...result.products]);
        setLoading(false);
      }
      console.log(result);
    } catch (e) {
      console.log(e);
      setLoading(false);
    }
  }

  useEffect(() => {
    fetchingProducts();
  }, [count]);

  if (loading) {
    return <div>Loading Data! Please wait for sometime</div>;
  }
  useEffect(() => {
    if (products && products.length === 100) setDisableButton(true);
  }, [products]);

  return (
    <div className="load-more-container">
      <div className="product-container">
        {products && products.length
          ? products.map((item) => (
              <div className="product" key={item.id}>
                <img src={item.thumbnail} alt={item.title} />
                <p>{item.title}</p>
              </div>
            ))
          : null}
      </div>

      <div className="button-container">
        <button disabled={disableButton} onClick={() => setCount(count + 1)}>
          Load More Products
        </button>
        {disableButton ? <p>You have reached 100 products</p> : null}
      </div>
    </div>
  );
}
问题原因

React Hook的核心规则之一:所有Hook必须在组件的顶层作用域调用,不能放在条件判断、循环或者嵌套函数里。你的代码中,第二个useEffect被放在了if (loading) return语句之后——当loading为true时,组件会提前返回,这个useEffect根本不会被执行,导致组件每次渲染时调用的Hook数量不一致,触发了"Rendered fewer hooks than expected"错误。

修复方案

把第二个useEffect移到组件的顶层,放在所有条件判断语句之前,确保每次渲染时所有Hook都能被调用。修复后的代码如下:

import React, { useEffect, useState } from "react";
import "./style.css";

export default function LoadMoreImages() {
  const [products, setProducts] = useState([]);
  const [count, setCount] = useState(0);
  const [loading, setLoading] = useState(false);
  const [disableButton, setDisableButton] = useState(false);

  async function fetchingProducts() {
    try {
      setLoading(true);
      const response = await fetch(
        `https://dummyjson.com/products?limit=20&skip=${
          count === 0 ? 0 : count * 20
        }`
      );
      const result = await response.json();

      if (result && result.products && result.products.length) {
        setProducts((prevData) => [...prevData, ...result.products]);
        setLoading(false);
      }
      console.log(result);
    } catch (e) {
      console.log(e);
      setLoading(false);
    }
  }

  useEffect(() => {
    fetchingProducts();
  }, [count]);

  // 移到组件顶层,确保每次渲染都会执行
  useEffect(() => {
    if (products && products.length === 100) setDisableButton(true);
  }, [products]);

  if (loading) {
    return <div>Loading Data! Please wait for sometime</div>;
  }

  return (
    <div className="load-more-container">
      <div className="product-container">
        {products && products.length
          ? products.map((item) => (
              <div className="product" key={item.id}>
                <img src={item.thumbnail} alt={item.title} />
                <p>{item.title}</p>
              </div>
            ))
          : null}
      </div>

      <div className="button-container">
        <button disabled={disableButton} onClick={() => setCount(count + 1)}>
          Load More Products
        </button>
        {disableButton ? <p>You have reached 100 products</p> : null}
      </div>
    </div>
  );
}
额外优化建议
  • 简化products的判断:直接用{products.length ? ... : null}即可,因为useState初始化的是空数组,products永远不会是null或undefined。
  • 在fetchingProducts里添加产品数量判断,当已加载100个产品时直接终止请求,避免无效调用。

内容的提问来源于stack exchange,提问作者Junaid khan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 00:53:16