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

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实例:

  1. 创建独立的Context文件
    在src目录下新建contexts/SlideContext.js:
import { createContext } from '@wordpress/element';

export const SlideContext = createContext();
  1. 修改Slider的edit.js导入路径
    将原来的import { SlideContext } from './edit'改为从共享Context文件导入:
import { SlideContext } from '../contexts/SlideContext';
  1. 修改Slide的edit.js导入路径
    同样将导入路径改为共享Context文件:
import { SlideContext } from '../contexts/SlideContext';
  1. 验证编译与加载
    确保build过程包含这个新的Context文件,或者在区块的block.json中正确配置依赖(如果使用@wordpress/scripts,默认会处理这些模块导入)。

额外验证点

  • 确认Slide区块确实是作为Slider区块的InnerBlocks子元素存在,只有当子组件在Context.Provider的包裹范围内时,才能读取到Context值。
  • 检查控制台是否有模块加载错误,确保Context文件路径正确。

内容的提问来源于stack exchange,提问作者Grzes Slania

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 13:27:26