自定义Gutenberg块setAttribute函数在保存/发布时失效原因排查
自定义Gutenberg块setAttribute无法配合保存/发布按钮工作的原因分析
问题现象
自定义Gutenberg块的侧边栏包含增减按钮,用于调整后端存储的数组长度,但出现以下异常:
- 站点编辑器保存或文章发布后刷新页面,数组长度未发生变化
- 点击增加按钮后,保存按钮仍处于禁用状态
- 文章中使用该块时,发布按钮显示激活但并未实际保存数组
相关代码
block.json
{ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 2, "name": "create-block/demo-block", "version": "0.1.0", "title": "Demo Block", "category": "widgets", "icon": "smiley", "description": "Example block scaffolded with Create Block tool.", "attributes": { "arr": { "type": "array", "default": [] } }, "supports": { "html": false }, "textdomain": "demo-block", "editorScript": "file:./index.js" }
edit.js
import { useBlockProps, InspectorControls } from '@wordpress/block-editor'; import { Panel, PanelBody } from '@wordpress/components'; import './editor.scss'; import { DemoObject } from './demo'; export default function Edit({ attributes, setAttributes }) { return ( <> <InspectorControls> <Panel> <PanelBody title='Demo Setting'> <DemoObject arr = { attributes.arr } update = { (newArr) => setAttributes({ arr: newArr }) } /> </PanelBody> </Panel> </InspectorControls> <p { ...useBlockProps() }> { 'Demo Block – hello from the editor!' } </p> </> ); }
demo.js
import { Component } from '@wordpress/element'; import { Button } from '@wordpress/components'; export class DemoObject extends Component { constructor(props) { super(props); this.state = { arr: props.arr, updater: props.update } this.increase = this.increase.bind(this); this.decrease = this.decrease.bind(this); } increase() { let newArr = this.state.arr; newArr.push(""); this.setState({ arr: newArr }); this.state.updater(newArr); } decrease() { if (this.state.arr.length > 0) { let newArr = this.state.arr; newArr.pop(); this.setState({ arr: newArr }); this.state.updater(newArr); } } render() { return( <div> <Button onClick={ this.decrease }>decrease</Button> <p>{ this.state.arr.length }</p> <Button onClick={ this.increase }>increase</Button> </div> ) } }
原因分析
核心问题是直接修改了数组的原引用,导致Gutenberg无法检测到属性变化。
在demo.js的increase和decrease方法中,let newArr = this.state.arr;只是获取了原数组的引用,后续的push/pop操作都是直接修改原数组本身,而非创建新的数组实例。Gutenberg基于React的浅比较机制检测属性变更,对于数组这类引用类型,只有当引用发生变化时才会识别为属性更新:
- 因为引用未变,保存按钮无法感知到属性变化,因此保持禁用状态
- 即使发布按钮偶然激活,后端也不会接收到更新后的数组,因为属性的引用没有改变,Gutenberg不会标记该块为已修改
修复方案
修改demo.js中的方法,通过创建数组副本的方式修改,确保每次更新都生成新的数组引用:
// 修改increase方法 increase() { // 扩展运算符创建原数组的副本 let newArr = [...this.state.arr]; newArr.push(""); this.setState({ arr: newArr }); this.props.update(newArr); } // 修改decrease方法 decrease() { if (this.state.arr.length > 0) { // 扩展运算符创建原数组的副本 let newArr = [...this.state.arr]; newArr.pop(); this.setState({ arr: newArr }); this.props.update(newArr); } }
同时优化组件状态管理,不需要将props.update存入组件state,直接使用this.props.update即可避免state与props不同步的问题,修改后的构造函数:
constructor(props) { super(props); this.state = { arr: props.arr }; this.increase = this.increase.bind(this); this.decrease = this.decrease.bind(this); }
内容的提问来源于stack exchange,提问作者Rodolfo
相关产品推荐
相关产品推荐

