React Context.Provider传值后子组件useContext返回undefined问题
WordPress区块开发:Context在父子区块间传递失效问题
开发WordPress区块时遇到以下问题:父组件Slider的Edit组件中创建了SlideContext,并通过Context.Provider传入包含setSlideRef的value,但子组件Slide的Edit组件使用useContext导入该Context后,返回值为undefined,无法定位问题所在。
文件夹结构
src slider edit.js index.js slide edit.js index.js contexts // 后续新增目录 SlideContext.js build slider index.js slide index.js
相关代码
Slider的index.js代码
import { registerBlockType } from '@wordpress/blocks'; import './style.scss'; /** * Internal dependencies */ import Edit from './edit'; import save from './save'; import metadata from './block.json'; registerBlockType( metadata.name, { edit: Edit, save, } );
Slider的edit.js代码
import React, { useRef } from 'react' import { useBlockProps, InnerBlocks } from '@wordpress/block-editor' import { SlideContext } from '../contexts/SlideContext'; // 后续修改导入路径 export default function Edit() { const slideRefs = useRef([]) const setSlideRef = (ref, index) => { slideRefs.current[index] = ref console.log('setSlideRef called with ref:', ref, 'and index:', index) } // 省略部分代码 console.log('Rendering Slider component with context value:', { setSlideRef }) const blockProps = useBlockProps() return ( <SlideContext.Provider value={{ setSlideRef }}> <div {...blockProps}> <div className='splash-slider__wrapper'> <div className='splash-slider__track' > <InnerBlocks allowedBlocks={['splash-blocks/slide']} renderAppender={() => <InnerBlocks.ButtonBlockAppender />} templateLock={false} /> </div> </div> </div> </SlideContext.Provider> ) }
Slide的edit.js代码
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor' import { useEffect, useRef, useContext } from '@wordpress/element' import { SlideContext } from '../contexts/SlideContext'; // 后续修改导入路径 export default function Edit({ attributes, setAttributes, clientId }) { const blockProps = useBlockProps({ className: 'splash-slider__slide' }) const slideRef = useRef() const slideContext = useContext(SlideContext) console.log('slideContext:', slideContext) // 日志输出:undefined const { setSlideRef } = slideContext || {} useEffect(() => { console.log('slideRef.current:', slideRef.current) // 日志输出正常 if (setSlideRef && slideRef.current) { console.log('Setting slideRef with clientId:', clientId) setSlideRef(slideRef, clientId) } }, [setSlideRef, clientId]) return ( <div {...blockProps} ref={slideRef}> {/* 省略InspectorControls和PanelBody代码 */} <InnerBlocks /> </div> ) }
问题原因
核心问题是WordPress区块的独立编译机制:每个区块会被编译为独立的bundle文件(build目录下的slider/index.js和slide/index.js)。当前Slide区块直接从../slider/edit导入SlideContext,在开发环境可能暂时正常,但编译后,Slide和Slider会各自持有一个独立的SlideContext实例,导致子组件无法读取到父组件提供的Context值。
解决方案
将SlideContext抽离为独立的共享模块,确保父子区块使用同一个Context实例:
- 创建独立的Context文件
在src目录下新建contexts/SlideContext.js:
import { createContext } from '@wordpress/element'; export const SlideContext = createContext();
- 修改Slider的edit.js导入路径
将原来的import { SlideContext } from './edit'改为从共享Context文件导入:
import { SlideContext } from '../contexts/SlideContext';
- 修改Slide的edit.js导入路径
同样将导入路径改为共享Context文件:
import { SlideContext } from '../contexts/SlideContext';
- 验证编译与加载
确保build过程包含这个新的Context文件,或者在区块的block.json中正确配置依赖(如果使用@wordpress/scripts,默认会处理这些模块导入)。
额外验证点
- 确认Slide区块确实是作为Slider区块的
InnerBlocks子元素存在,只有当子组件在Context.Provider的包裹范围内时,才能读取到Context值。 - 检查控制台是否有模块加载错误,确保Context文件路径正确。
内容的提问来源于stack exchange,提问作者Grzes Slania
相关产品推荐
相关产品推荐

