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

WordPress自定义Tab区块复制标签时报Rendered more hooks错误如何解决

问题原因与解决方案

你遇到的Rendered more hooks than during the previous render是React Hooks的典型规则违例错误,核心是两次渲染过程中调用的Hook数量不一致,结合你提供的代码,触发问题的根源有三个:

  • 你在test.map循环渲染<Tab>组件时没有给每一项指定唯一稳定的key属性,React会错误复用DOM节点,<RichText>内部自带Hooks逻辑,节点复用时就会出现Hook数量不匹配的报错
  • 你复制标签项时直接复用了原对象的引用,没有生成新的唯一标识,同时更新状态后没有同步到WordPress的区块属性tabContent,导致本地状态和区块属性不一致
  • <Tabs>组件的activeTab属性写死为字符串"1",和你用useState存储的数字类型激活标签状态count不匹配,切换、新增标签时状态紊乱

修复步骤

  1. 给每个标签项添加唯一id字段,循环渲染时用id作为key,不要用数组索引
  2. 调整复制逻辑,深拷贝要复制的标签项并生成新的唯一id,更新本地状态后同步到区块属性
  3. 统一激活标签的类型,把<Tabs>的activeTab绑定到你存储的count状态
  4. 确保所有Hooks都在组件顶层调用,不要放在循环、条件判断内部

修复后核心代码

// Edit function (负责wp-admin文章编辑界面逻辑)
const edit = props => {
    const { tabContent } = props.attributes;

    // 初始化状态,注意每个tab项都要提前有唯一id字段,新建标签时也需要生成
    const [test, handleUpdate] = useState(tabContent);
    // 统一激活标签为数字类型,和Tabs组件回调返回的类型对齐
    const [count, setTab] = useState(1);
    
    const correctID = count - 1;

    const onClickDuplicate = () => {
        // 直接取当前激活的标签项,不用filter
        const targetItem = test[correctID];
        // 深拷贝原标签项,生成新的唯一id,避免引用关联
        const duplicatedItem = {
            ...targetItem,
            // 用时间戳生成临时唯一id,也可以用你自己的id生成规则
            id: Date.now()
        };
        const newArray = [...test, duplicatedItem];
        // 同时更新本地状态和区块属性,避免数据不一致
        handleUpdate(newArray);
        props.setAttributes({ tabContent: newArray });
    };

    // 把更新标题、内容的方法定义在组件顶层,不要放在map循环里
    const onChangeTabUpdateTitle = (value, index) => {
        const newArray = [...test];
        newArray[index].title = value;
        handleUpdate(newArray);
        props.setAttributes({ tabContent: newArray });
    };

    const onChangeTabUpdateContent = (value, index) => {
        const newArray = [...test];
        newArray[index].content = value;
        handleUpdate(newArray);
        props.setAttributes({ tabContent: newArray });
    };

    return (
        <Fragment>
            <InspectorControls>
                <PanelBody title={ __('test') }>
                </PanelBody>
            </InspectorControls>
            <BlockControls
                controls={ [
                    {
                        icon: <BiChevronLeft />,
                        title: __( 'Links' ),
                        onClick: () => {
                            console.log('links')
                        },
                    },
                    {
                        icon: <BiChevronRight />,
                        title: __( 'Rechts' ),
                        onClick: () => {
                            console.log('rechts')
                        },
                    },
                    {
                        icon: <BiPlus />,
                        title: __( 'Toevoegen' ),
                        onClick: () => {
                            console.log('toevoegen')
                        },
                    },
                    {
                        icon: <BiDuplicate />,
                        title: __( 'Duplicate' ),
                        onClick: onClickDuplicate,
                    },
                    {
                        icon: <BiTrash />,
                        title: __( 'Verwijderen' ),
                        onClick: () => {
                            console.log('verwijderen')
                        },
                    },
                ] }
            />
            {/* 把activeTab绑定到count状态,转成字符串和组件要求的类型对齐 */}
            <Tabs 
                activeTab={String(count)} 
                className="" 
                ulClassName="" 
                activityClassName="bg-success" 
                onClick={(event, tab) => setTab(Number(tab))} 
            >
                {/* 用tab的唯一id作为key,同时把索引传给更新方法 */}
                {test.map((tabs, index) => { 
                    return (
                        <Tab 
                            key={tabs.id}
                            title={
                                <RichText 
                                    placeholder={__("Tab", "podkit")}
                                    value={tabs.title}
                                    onChange={(val) => onChangeTabUpdateTitle(val, index)}
                                    allowedFormats={ [ 'core/bold' ] }
                                />
                            } 
                            className="mr-3"
                        >
                            <RichText 
                                placeholder={__("Content", "podkit")}
                                value={tabs.content}
                                onChange={(val) => onChangeTabUpdateContent(val, index)}
                            />
                        </Tab>
                    ) 
                })}
            </Tabs>
        </Fragment>
    );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 23:06:04