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

React组件出现Rendered more hooks错误,求原因排查

错误原因分析

错误提示"Rendered more hooks than during the previous render."的核心原因是违反了React Hooks的调用规则:所有Hooks必须在组件的顶层作用域调用,不能放在条件判断、循环或者return语句之后。

你的代码里,const [img, setImg] = useState(...)这行Hook调用是在if(fetching)和if(error)的return语句之后的。当组件处于fetching(加载中)或error(请求错误)状态时,会提前return,这部分Hook不会被执行;而当数据加载完成后,组件会继续执行到这行Hook,导致两次渲染的Hook数量不一致,触发报错。

修复方案

把useState移到组件顶层,初始值设为安全的默认值(比如null),然后用useEffect监听gallery数据的变化,在数据就绪后更新img状态:

export default function ProductDetails() {
    // 所有Hooks必须放在组件顶层,条件判断之前
    const {qty, increaseQty, decreaseQty, onAdd, setQty} = useStateContext();
    const [img, setImg] = useState(null); // 初始值设为null
    const {query} = useRouter();
    const [results] = useQuery({
        query: GET_PRODUCT_QUERY,
        variables: {slug: query.slug}
    });

    useEffect(() => {
        setQty(1);
    }, []);

    const {data, fetching, error} = results;

    // 数据加载或错误时提前返回
    if(fetching) return <p>Loading...</p>;
    if(error) return <p>Oh no....</p>;

    // 提取产品数据
    const {title,description, image, gallery } = data.products.data[0].attributes;

    // 监听gallery数据,就绪后更新img状态
    useEffect(() => {
        if(gallery?.data?.[0]?.attributes?.formats?.medium?.url) {
            setImg(gallery.data[0].attributes.formats.medium.url);
        }
    }, [gallery]);

    console.log(img);

    // 提示弹窗逻辑
    const notify = () => {
        toast.success(`${title} added to your cart`, {duration: 1500});
    }

    return(
        <DetailsStyle>
            <Gallery>
                {/* 渲染时做可选链判断,避免初始值为null时报错 */}
                <img src={img || gallery.data[0].attributes.formats.medium.url} alt={title} />
                <Thumbnails>
                    {gallery.data.map((image, index) => (
                            <SingleThumb key={index} >
                                <img src={image.attributes.formats.thumbnail.url} alt={title} />
                            </SingleThumb>
                        )
                    )}
                </Thumbnails>
            </Gallery>
            <ProductInfo>
                <h3>{title}</h3>
                <p>{description}</p>
                <Quantity>
                    <span>Quantity</span>
                    <button><AiFillMinusCircle onClick={decreaseQty} /></button>
                    <p>{qty}</p>
                    <button><AiFillPlusCircle onClick={increaseQty}/></button>
                </Quantity>
                <Buy onClick={() => {
                    onAdd(data.products.data[0].attributes, qty)
                    notify();
                }}>Add To Cart</Buy>
            </ProductInfo>
        </DetailsStyle>
    )
}
关键注意点
  • 所有Hooks(useState、useEffect、useQuery等)必须在组件最顶层调用,不能被任何条件语句包裹或放在条件return之后。
  • 给Hook初始值设置安全默认值(比如null),避免数据未就绪时访问深层属性导致报错。
  • 使用useEffect监听依赖数据变化,确保状态更新时机正确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 23:25:27