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

React自定义钩子执行过多触发Minified Error #185问题求助

React最大更新深度错误(Footer组件+useLogoImageUrl钩子)

问题描述

React组件Footer使用自定义钩子useLogoImageUrl时,钩子执行51次后抛出React压缩版错误#185,提示超出最大更新深度,这类错误通常由组件反复调用setState触发循环渲染导致。该组件是WP Block,仅在保存为Pattern时出现此错误。

涉及代码

import { useLogoImageUrl } from '../../../src/hooks/useLogoImageUrl';

const Item = ({ item }) => (
    <div key={item.id}>
        <strong>{item.title}</strong>
        {item.children?.length > 0 && (
            <ul>
                {item.children.map(subitem => (
                    <li key={subitem.id}>
                        <a href={subitem.url}>{subitem.title}</a>
                    </li>
                ))}
            </ul>
        )}
    </div>
);

/**
 * Global Footer Component
 *
 * @param {Object} params
 * @param {string} params.logoImageUrl
 * @param {Array|null} params.menu
 * @param {string} params.instagramLink
 * @param {string} params.youtubeLink
 * ...
 * @param {string} params.sitemapLink
 * ...
 */
export const Footer = ({
    menu = [],
    logoImageUrl,
    instagramLink,
    // ...
    sitemapLink,
    // ...
}) => {
    const selectedLogoUrl = useLogoImageUrl(logoImageUrl);

    const currentYear = new Date().getFullYear();
    const splitMenuData = menu?.reduce((acc, item, index) => {
        const chunkIndex = Math.floor(index / 2);
        if (!acc[chunkIndex]) {
            acc[chunkIndex] = [];
        }
        acc[chunkIndex].push(item);
        return acc;
    }, []);

    return (
        <footer>
            <div>
                <div>
                    <div>
                        <a href="/" aria-label='logo'>
                            <img src={selectedLogoUrl} alt="Logo" />
                        </a>
                        <div>
                            {/* Some hardcoded links */}
                        </div>
                        <div>
                            {instagramLink && (
                                <a href={instagramLink} target="_blank" rel="noreferrer noopener">
                                    <img src="/path/to/instagram.svg" alt="Instagram" />
                                </a>
                            )}
                            {/* ... */}
                        </div>
                    </div>
                    <hr />
                    <nav>
                        {splitMenuData?.map(row =>
                            row.map(item => (
                                <Item item={item} key={item.id} />
                            ))
                        )}
                    </nav>
                </div>
                <hr />
                <div>
                    <ul>
                        {sitemapLink && (
                            <li>
                                <a href={sitemapLink}>Sitemap</a>
                            </li>
                        )}
                        {/* ... */}
                    </ul>
                </div>
            </div>
        </footer>
    );
};

原自定义钩子useLogoImageUrl

import {
    DEFAULT_LOGO_IMAGE_DARK_SRC,
    DEFAULT_HERO_IMAGE_LIGHT_SRC,
    STYLE_MODE_DARK,
} from '../constants';

export const useLogoImageUrl = ( path, styleMode ) => {
    const isDark = styleMode === STYLE_MODE_DARK;

    return (
        path ||
        ( isDark ? DEFAULT_HERO_IMAGE_LIGHT_SRC : DEFAULT_LOGO_IMAGE_DARK_SRC )
    );
};

修改后的自定义钩子(尝试useMemo后)

import { useMemo } from '@wordpress/element';
import {
    DEFAULT_LOGO_IMAGE_DARK_SRC,
    DEFAULT_HERO_IMAGE_LIGHT_SRC,
    STYLE_MODE_DARK,
} from '../constants';

export const useLogoImageUrl = ( path, styleMode ) => {
    console.log( styleMode );
    const isDark = 'dark' === STYLE_MODE_DARK;

    return useMemo( () => {
        return (
            path ||
            ( isDark
                ? DEFAULT_HERO_IMAGE_LIGHT_SRC
                : DEFAULT_LOGO_IMAGE_DARK_SRC )
        );
    }, [ path, isDark ] );
};

已尝试的无效方案

  • 在组件和自定义钩子中使用useMemo()
  • 注释掉Item组件

问题排查与修复

1. 修复自定义钩子的逻辑错误

修改后的钩子存在硬编码错误,导致isDark值固定无法动态切换:

// 错误写法:将常量与字符串直接比较,isDark成为固定值
const isDark = 'dark' === STYLE_MODE_DARK;
// 正确写法:使用传入的styleMode参数判断主题模式
const isDark = styleMode === STYLE_MODE_DARK;

2. 补全钩子调用的缺失参数

Footer组件调用useLogoImageUrl时仅传入了logoImageUrl,缺少styleMode参数,导致钩子中styleMode为undefined。需补全参数(示例以WP的主题模式获取逻辑为例,根据实际场景调整):

// 先获取当前主题模式,示例从WP设置中获取
const styleMode = useSetting('appearance/styleMode');
// 补全钩子调用参数
const selectedLogoUrl = useLogoImageUrl(logoImageUrl, styleMode);

3. 稳定化组件内计算逻辑

splitMenuData每次渲染都会生成新数组,触发子组件不必要重渲染,用useMemo包裹稳定化:

const splitMenuData = useMemo(() => {
    return menu?.reduce((acc, item, index) => {
        const chunkIndex = Math.floor(index / 2);
        if (!acc[chunkIndex]) {
            acc[chunkIndex] = [];
        }
        acc[chunkIndex].push(item);
        return acc;
    }, []);
}, [menu]);

4. 排查WP Block保存逻辑

由于错误仅在保存为Pattern时出现,需确认:

  • Block的save函数是否正确序列化组件输出,避免保存流程触发循环渲染
  • logoImageUrl等属性在保存时是否被动态修改,导致每次渲染生成新值,触发钩子与组件反复更新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 22:42:05