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不匹配,切换、新增标签时状态紊乱
修复步骤
- 给每个标签项添加唯一id字段,循环渲染时用id作为key,不要用数组索引
- 调整复制逻辑,深拷贝要复制的标签项并生成新的唯一id,更新本地状态后同步到区块属性
- 统一激活标签的类型,把
<Tabs>的activeTab绑定到你存储的count状态 - 确保所有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
相关产品推荐
相关产品推荐

