WordPress自定义区块:动态更新Block Templates数据不渲染问题排查
问题
开发WordPress自定义区块时,尝试在首次useEffect调用后用获取到的属性数据动态更新Block Templates。首次渲染时属性为空,显示默认值;跟踪代码发现模板已更新,但调用useInnerBlocksProps传入修订后的模板后,数据仍未渲染到界面。已确认最后一次渲染的模板定义正确,但界面显示不符,请问遗漏了什么?
export default function Edit(props) { const { PanelBody, PanelRow } = wp.components; const { attributes, setAttributes } = props; useEffect(() => { setAttributes({'name': 'Edward Alan Thompson'}); setAttributes({'birth_date': '1 jan 1900'}); setAttributes({'death_date': '31 Dec 1990'}); setAttributes({'imageUrl': 'http://wordpressdevel.local/wp-content/uploads/2022/07/1.png'}); }, []); const blockProps = useBlockProps( { style:{minHeight: 40, width: '100%', border: "1px dotted red"} }); const innerBlocksProps = useInnerBlocksProps( {orientation: "horizontal"}, {template: [ [ 'core/columns', { columns: 2 }, [ [ 'core/column', {width: "20%"}, [ [ 'core/image', { url: attributes.imageUrl??''} ] ] ], [ 'core/column', {}, [ [ 'core/heading', { content: attributes.name??''} ], [ 'core/paragraph', { content: 'b. ' + attributes.birth_date??''} ], [ 'core/paragraph', { content: 'd. ' + attributes.death_date??''} ] ] ], ] ] ]} ); return ( <div > <InspectorControls> <PanelBody title="General" initialOpen={true}> <PanelRow> </PanelRow> </PanelBody> </InspectorControls> <div {...blockProps}> <div {...innerBlocksProps}></div></div> </div> ); }
解决方案
核心问题是:useInnerBlocksProps的模板仅在区块首次初始化时生效一次,后续属性更新不会自动重新应用模板。要实现动态更新,需要手动同步内部区块内容:
步骤1:引入必要的工具函数
用到wp.data的select和dispatch来操作内部区块,以及wp.blocks的模板解析方法。步骤2:监听属性变化,手动更新内部区块
在属性更新时,重新构建模板并替换内部区块内容。修改后的完整代码如下:
import { useEffect } from '@wordpress/element'; import { useSelect, useDispatch } from '@wordpress/data'; import { useBlockProps, useInnerBlocksProps, InspectorControls } from '@wordpress/block-editor'; export default function Edit(props) { const { PanelBody, PanelRow } = wp.components; const { attributes, setAttributes, clientId } = props; const { getBlocks } = useSelect('core/block-editor'); const { replaceInnerBlocks } = useDispatch('core/block-editor'); // 首次初始化属性 useEffect(() => { setAttributes({ name: 'Edward Alan Thompson', birth_date: '1 jan 1900', death_date: '31 Dec 1990', imageUrl: 'http://wordpressdevel.local/wp-content/uploads/2022/07/1.png' }); }, []); // 属性更新时同步内部区块 useEffect(() => { // 确保属性都已加载完成 if (!attributes.name || !attributes.imageUrl) return; // 构建最新的内部区块模板 const newTemplate = [ [ 'core/columns', { columns: 2 }, [ [ 'core/column', {width: "20%"}, [ [ 'core/image', { url: attributes.imageUrl } ] ] ], [ 'core/column', {}, [ [ 'core/heading', { content: attributes.name } ], [ 'core/paragraph', { content: `b. ${attributes.birth_date}` } ], [ 'core/paragraph', { content: `d. ${attributes.death_date}` } ] ] ], ] ] ]; // 将模板转换为区块编辑器可识别的对象格式 const parsedBlocks = wp.blocks.parseBlocksFromTemplate(newTemplate); // 替换当前区块的内部内容 replaceInnerBlocks(clientId, parsedBlocks, false); }, [attributes.name, attributes.birth_date, attributes.death_date, attributes.imageUrl, clientId, replaceInnerBlocks]); const blockProps = useBlockProps( { style:{minHeight: 40, width: '100%', border: "1px dotted red"} }); // 保留初始化模板,后续更新由useEffect处理 const innerBlocksProps = useInnerBlocksProps( {orientation: "horizontal"}, { template: [ [ 'core/columns', { columns: 2 }, [ [ 'core/column', {width: "20%"}, [ [ 'core/image', { url: ''} ] ] ], [ 'core/column', {}, [ [ 'core/heading', { content: ''} ], [ 'core/paragraph', { content: ''} ], [ 'core/paragraph', { content: ''} ] ] ], ] ] ], templateLock: 'all' // 可选:锁定模板防止用户手动修改 } ); return ( <div > <InspectorControls> <PanelBody title="General" initialOpen={true}> <PanelRow> </PanelRow> </PanelBody> </InspectorControls> <div {...blockProps}> <div {...innerBlocksProps}></div> </div> </div> ); }
- 关键注意点
template仅负责区块首次渲染的初始结构,后续动态更新必须通过replaceInnerBlocks手动触发;- 监听属性的
useEffect要把所有需要触发更新的属性加入依赖数组,确保属性变化时执行同步逻辑; clientId是当前区块的唯一标识,用来定位要更新的内部区块容器;wp.blocks.parseBlocksFromTemplate是将模板数组转换为区块对象的必要步骤,不能省略。
内容的提问来源于stack exchange,提问作者ed4becky
相关产品推荐
相关产品推荐

