WordPress Gutenberg块编辑器中react-router跨块使用报错问题
核心结论
不能判定Gutenberg内所有块默认相互隔离、无法通过React组件或Context实现块间直接通信。你遇到的react-router上下文丢失报错,和Gutenberg序列化/解析层面的块隔离逻辑无关,本质是插件构建配置错误导致的Context实例不匹配。
根因说明
- Gutenberg提到的块隔离是数据存储层面的:每个块的序列化内容独立存储、解析,不会互相污染保存到数据库的内容结构,不是React渲染树层面的硬隔离。正常同一份React运行时环境下,父块组件包裹的React Context完全可以被
InnerBlocks渲染的子块组件读取,编辑器本身的块选中状态、编辑模式等全局状态就是靠React Context跨块传递的。 - 你的报错来自依赖重复打包:
@wordpress/scripts默认会把dependencies下声明的react-router-dom完整打包进每个块的构建bundle里,父块和子块的bundle各自包含一份独立的react-router-dom代码,会生成完全独立的Context对象。哪怕DOM结构上是父子嵌套,父块MemoryRouter提供的Context和子块Routes组件读取的Context根本不是同一个内存实例,自然会抛出“未在Router上下文内”的错误。
修复步骤
1. 调整构建配置,避免重复打包路由依赖
首先修改插件根目录的package.json,把react-router-dom从dependencies字段移到devDependencies,避免wp-scripts默认把它打包进每个块的产物。
在插件根目录新建webpack.config.js,继承官方默认配置,把react-router-dom设为外部依赖,打包时不打入bundle:
const defaultConfig = require('@wordpress/scripts/config/webpack.config'); module.exports = { ...defaultConfig, externals: { ...defaultConfig.externals, 'react-router-dom': 'ReactRouterDOM', } };
2. 注册全局共用的路由依赖
在插件负责注册块的PHP文件中,提前将react-router-dom的UMD构建文件注册为全局脚本(将UMD文件存放在你自己插件的资产目录下,注册时指向本地插件内的文件路径即可),并在注册两个自定义块时将该脚本设为依赖,保证父块、子块加载时都共用同一份react-router-dom实例,Context对象唯一。
示例PHP代码:
function my_custom_blocks_register() { // 注册全局共用的react-router-dom脚本 wp_register_script( 'react-router-dom-global', plugins_url( 'assets/vendor/react-router-dom.umd.min.js', __FILE__ ), [ 'react', 'react-dom' ], '6.3.0' ); // 注册父块,添加全局路由脚本依赖 register_block_type( __DIR__ . '/build/react-router-wrapper-block', [ 'editor_script_deps' => [ 'react-router-dom-global' ] ] ); // 注册子块,同样添加依赖 register_block_type( __DIR__ . '/build/react-router-single-route', [ 'editor_script_deps' => [ 'react-router-dom-global' ] ] ); } add_action( 'init', 'my_custom_blocks_register' );
3. 修复现有代码的属性冲突问题
父块react-router-wrapper-block/edit.js中,你给外层div和内层路由链接容器都绑定了{...blockProps},blockProps包含块唯一ID等自定义属性,重复绑定会引发DOM属性冲突,删除内层div上的{...blockProps}即可。
可选替代方案
如果你不想手动处理依赖打包问题,也可以用Gutenberg原生能力实现块间通信:
- 用
@wordpress/data创建自定义全局状态存储,父子块通过统一的store读写状态,不依赖React Context穿透 - 用官方原生的Block Context API,父块声明要向下传递的上下文属性,子块声明接收对应属性,是官方专门提供的父子块传值能力,稳定性更高
内容的提问来源于stack exchange,提问作者Che Shy
相关产品推荐
相关产品推荐

