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

自定义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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 15:09:58