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

React中无需中间组件与Redux,实现孙组件向祖父组件传值

当然可行!两种不依赖中间组件/Redux的实现方案

完全可以实现GrandChild直接向AboutUs传递状态,不需要借助AboutUsChild当“传声筒”,也不用Redux这类状态管理库。下面给你两种实用的方案,都是基于你提供的代码修改的:

方案一:React Context API(官方推荐)

Context API就是React官方为跨层级传递数据/方法设计的,完美匹配你的场景:

1. 创建Context

首先创建一个Context实例,用来承载祖父组件的状态更新方法:

import React, { Component, createContext } from 'react';

// 创建Context
const ChildToParentContext = createContext();

2. 在AboutUs中提供Context

修改AboutUs组件,用ChildToParentContext.Provider包裹子组件,把更新状态的方法传递下去:

class AboutUs extends Component {
  constructor(props) {
    super(props);
    this.state = { childState: false };
  }

  // 改用箭头函数,避免手动绑定this
  myMethod = (value) => {
    this.setState({ childState: value });
  };

  render() {
    console.log('AboutUs', this.state.childState);
    return (
      {/* 用Provider包裹所有子组件,传递更新方法 */}
      <ChildToParentContext.Provider value={this.myMethod}>
        <div>
          <h1 className={`title ${this.state.childState ? 'on' : ''}`}>
            About us {this.props.aboutusProp}
          </h1>
          <AboutUsChild />
        </div>
      </ChildToParentContext.Provider>
    );
  }
}

3. 在GrandChild中消费Context

修改GrandChild组件,直接从Context中获取祖父的方法,完全不需要中间组件传递props:

class GrandChild extends Component {
  constructor() {
    super();
    this.state = { TitleClick: false };
  }

  TitleClick = () => {
    const newState = !this.state.TitleClick;
    this.setState({ TitleClick: newState });
    // 直接调用Context里的方法更新祖父组件状态
    this.context(newState);
  };

  // 声明该组件要使用的Context
  static contextType = ChildToParentContext;

  render() {
    console.log('GrandChild', this.state.TitleClick);
    return (
      <div>
        {this.props.Method ? (
          <h1
            onClick={this.TitleClick}
            className={`title ${this.state.TitleClick ? 'on' : ''}`}
          >
            Grand Child
          </h1>
        ) : null}
        <h1>{this.props.children}</h1>
      </div>
    );
  }
}

修改后,AboutUsChild完全不用处理任何状态或方法的传递,GrandChild直接和AboutUs建立联系完成状态更新。

方案二:自定义事件总线(轻量快捷)

如果觉得Context有点繁琐,也可以用自定义事件的方式,本质是利用浏览器的事件监听机制:

1. 实现事件总线

可以单独写个工具对象,或者直接在组件里定义:

// 简单的事件总线实现
const eventBus = {
  // 监听事件
  on(event, callback) {
    document.addEventListener(event, callback);
  },
  // 触发事件
  emit(event, data) {
    document.dispatchEvent(new CustomEvent(event, { detail: data }));
  },
  // 移除监听,防止内存泄漏
  off(event, callback) {
    document.removeEventListener(event, callback);
  }
};

2. 在AboutUs中监听事件

修改AboutUs组件,在挂载时监听孙组件的更新事件,卸载时移除监听:

class AboutUs extends Component {
  constructor(props) {
    super(props);
    this.state = { childState: false };
    this.handleGrandChildUpdate = this.handleGrandChildUpdate.bind(this);
  }

  handleGrandChildUpdate(e) {
    // 从事件对象中获取孙组件传递的状态
    this.setState({ childState: e.detail });
  }

  componentDidMount() {
    // 监听孙组件的更新事件
    eventBus.on('grandchild:state-update', this.handleGrandChildUpdate);
  }

  componentWillUnmount() {
    // 组件卸载时一定要移除监听,避免内存泄漏
    eventBus.off('grandchild:state-update', this.handleGrandChildUpdate);
  }

  render() {
    console.log('AboutUs', this.state.childState);
    return (
      <div>
        <h1 className={`title ${this.state.childState ? 'on' : ''}`}>
          About us {this.props.aboutusProp}
        </h1>
        <AboutUsChild />
      </div>
    );
  }
}

3. 在GrandChild中触发事件

修改GrandChild组件,点击标题时触发事件传递状态:

class GrandChild extends Component {
  constructor() {
    super();
    this.state = { TitleClick: false };
  }

  TitleClick = () => {
    const newState = !this.state.TitleClick;
    this.setState({ TitleClick: newState });
    // 触发事件,把新状态传出去
    eventBus.emit('grandchild:state-update', newState);
  };

  render() {
    console.log('GrandChild', this.state.TitleClick);
    return (
      <div>
        {this.props.Method ? (
          <h1
            onClick={this.TitleClick}
            className={`title ${this.state.TitleClick ? 'on' : ''}`}
          >
            Grand Child
          </h1>
        ) : null}
        <h1>{this.props.children}</h1>
      </div>
    );
  }
}

这种方式完全绕过中间组件,但一定要注意在组件卸载时移除事件监听,避免内存泄漏。

总结

  • 优先推荐Context API:它是React官方方案,更符合React的设计模式,类型安全,维护起来也更省心。
  • 事件总线适合简单场景:轻量快捷,但大型项目里可能会导致事件逻辑混乱,需要谨慎使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:08:02