返回

React 组件通讯的那些“事儿”

前端

React 组件之间的通讯方式有很多种,每种方式都有其自身的优缺点。在实际开发中,我们需要根据具体情况选择最合适的方式。

父子组件之间的通讯

父子组件之间的通讯是最简单的一种通讯方式。父组件可以通过 props 向子组件传递数据,子组件可以通过 state 向父组件传递数据。

父组件向子组件传递数据

父组件可以通过 props 向子组件传递数据。props 是一个只读的对象,子组件可以通过 props 来访问父组件传递的数据。

// 父组件
class ParentComponent extends React.Component {
  render() {
    return (
      <div>
        <ChildComponent name="John" />
      </div>
    );
  }
}

// 子组件
class ChildComponent extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, {this.props.name}!</h1>
      </div>
    );
  }
}

子组件向父组件传递数据

子组件可以通过 state 向父组件传递数据。state 是一个可变的对象,子组件可以通过 setState() 方法来修改 state。父组件可以通过子组件的 props 来访问子组件的 state。

// 子组件
class ChildComponent extends React.Component {
  state = {
    count: 0
  };

  incrementCount = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <h1>Count: {this.state.count}</h1>
        <button onClick={this.incrementCount}>Increment</button>
      </div>
    );
  }
}

// 父组件
class ParentComponent extends React.Component {
  render() {
    return (
      <div>
        <ChildComponent />
      </div>
    );
  }
}

兄弟组件之间的通讯

兄弟组件之间的通讯可以分为两种情况:

  • 同级兄弟组件之间的通讯 :同级兄弟组件可以通过 props 来传递数据。
  • 非同级兄弟组件之间的通讯 :非同级兄弟组件之间的通讯可以使用 context、refs、render props 或高阶组件来实现。

同级兄弟组件之间的通讯

同级兄弟组件之间的通讯可以通过 props 来传递数据。

// 组件 A
class ComponentA extends React.Component {
  render() {
    return (
      <div>
        <ComponentB name="John" />
      </div>
    );
  }
}

// 组件 B
class ComponentB extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, {this.props.name}!</h1>
      </div>
    );
  }
}

非同级兄弟组件之间的通讯

非同级兄弟组件之间的通讯可以使用 context、refs、render props 或高阶组件来实现。

context

context 是一个共享的数据对象,可以被所有子组件访问。

// 父组件
class ParentComponent extends React.Component {
  state = {
    count: 0
  };

  render() {
    return (
      <div>
        <ChildComponentA />
        <ChildComponentB />
      </div>
    );
  }
}

// 子组件 A
class ChildComponentA extends React.Component {
  static contextType = MyContext;

  render() {
    return (
      <div>
        <h1>Count: {this.context.count}</h1>
      </div>
    );
  }
}

// 子组件 B
class ChildComponentB extends React.Component {
  static contextType = MyContext;

  render() {
    return (
      <div>
        <h1>Count: {this.context.count}</h1>
      </div>
    );
  }
}

// 创建 context 对象
const MyContext = React.createContext({
  count: 0
});

refs

refs 可以用来访问子组件的实例。

// 父组件
class ParentComponent extends React.Component {
  childRef = React.createRef();

  render() {
    return (
      <div>
        <ChildComponent ref={this.childRef} />
      </div>
    );
  }
}

// 子组件
class ChildComponent extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, {this.props.name}!</h1>
      </div>
    );
  }
}

render props

render props 是一个函数,可以被子组件调用。子组件可以通过 render props 来访问父组件的数据和方法。

// 父组件
class ParentComponent extends React.Component {
  state = {
    count: 0
  };

  render() {
    return (
      <div>
        <ChildComponent render={(count) => <h1>Count: {count}</h1>} />
      </div>
    );
  }
}

// 子组件
class ChildComponent extends React.Component {
  render() {
    return this.props.render(this.props.count);
  }
}

高阶组件

高阶组件是一个函数,可以用来包装其他组件。高阶组件可以通过 props 来向被包装的组件传递数据和方法。

// 高阶组件
const withCount = (WrappedComponent) => {
  return class extends React.Component {
    state = {
      count: 0
    };

    render() {
      return <WrappedComponent count={this.state.count} />;
    }
  };
};

// 被包装的组件
const ChildComponent = (props) => {
  return (
    <div>
      <h1>Count: {props.count}</h1>
    </div>
  );
};

// 使用高阶组件
const CountComponent = withCount(ChildComponent);

跨级组件之间的通讯

跨级组件之间的通讯可以使用 context、refs、render props 或高阶组件来实现。

// 父组件
class ParentComponent extends React.Component {
  state = {
    count: 0
  };

  render() {
    return (
      <div>
        <GrandchildComponent count={this.state.count} />
      </div>
    );
  }
}

// 子组件
class ChildComponent extends React.Component {
  render() {
    return (
      <div>
        <GrandchildComponent count={this.props.count} />
      </div>
    );
  }
}

// 孙组件
class GrandchildComponent extends React.Component {
  render() {
    return (
      <div>
        <h1>Count: {this.props.count}</h1>
      </div>
    );
  }
}

非嵌套组件之间的通讯

非嵌套组件之间的通讯可以使用 Redux、消息总线或自定义事件来实现。

Redux

Redux 是一个状态管理库,可以用来在组件之间共享数据。

// 创建 Redux store
const store = createStore(reducer);

// 父组件
class ParentComponent extends React.Component {
  componentDidMount() {
    store.subscribe(() => this.forceUpdate());
  }

  render() {
    return (
      <div>
        <ChildComponent />
      </div>
    );
  }
}

// 子组件
class ChildComponent extends React.Component {
  componentDidMount() {
    store.subscribe(() => this.forceUpdate());
  }

  render() {
    return (
      <div>
        <h1>Count: {store.getState().count}</h1>
      </div>
    );
  }
}

消息总线

消息总线是一个组件,可以用来在组件之间发送和接收消息。

// 创建消息总线
const bus = new EventEmitter();

// 父组件
class ParentComponent extends React.Component {
  componentDidMount() {
    bus.on('count-updated', () => this.forceUpdate());
  }

  render() {
    return (
      <div>
        <ChildComponent />
      </div>
    );
  }
}

// 子组件
class ChildComponent extends React.Component {
  componentDidMount() {
    bus.on('count-updated', () => this.forceUpdate());
  }

  incrementCount = () => {
    bus.emit