首页 > 解决方案 > 仅访问父级来反应兄弟级通信

问题描述

我正在尝试创建类似于React Bootstrap 的下拉组件的东西。我的起始骨架如下所示:

import React from 'react';

const DropDown = props => {
  return <div className="dropdown-container">{props.children}</div>;
};

const DropDownToggle = props => {
  return <div className="dropdown-toggle">{props.children}</div>;
};

const DropDownContent = props => {
  return <div className="dropdown-content">{props.children}</div>;
};

export { DropDown, DropDownToggle, DropDownContent };

这些组件将像这样使用:

<DropDown>
  <DropDownToggle>
    {/* 
      The content inside here should be customizable so the user of
      these components can specify whatever they want for the toggle
     */}
    <button type="button">
      my button
    </button>
  </DropDownToggle>
  <DropDownContent>
     {/* 
      The content inside here should be customizable so the user of
      these components can specify whatever they want for the content of 
      the dropdown
     */}
    <ContentComponent/>
  </DropDownContent>
</DropDown>

有没有办法可以在两个子组件(DropDownContent 和 DropDownToggle)之间进行通信?我可以访问父组件,到目前为止它只接收并显示子组件,但我想以某种方式在子组件之间进行通信,以便用户可以单击切换来打开/关闭内容。我不想使用 redux。

先感谢您!

编辑

我最终采用了@Train 在下面他/她的评论中建议的方法。我最初希望能够手动嵌套组件,但对我来说最重要的是让状态在父组件中是自包含的。能够定义切换按钮的 HTML 以及内容的 HTML 也是一项要求。我的最终实现允许这两种情况,看起来像这样:

import React from 'react';
import PropTypes from 'prop-types';

export class Dropdown extends React.Component {
  state = {
    isOpen: false,
  };

  onDropDownToggleClick = () => {
    this.setState({ isOpen: !this.state.isOpen });
  };

  render() {
    let contentClasses = 'dropdown-content';
    if (this.state.isOpen) {
      contentClasses += ' show';
    }

    return (
      <div className="dropdown-container">
        <div className="dropdown-toggle" onClick={this.onDropDownToggleClick}>
          {this.props.toggle}
        </div>
        <div className={contentClasses}>{this.props.content}</div>
      </div>
    );
  }
}

Dropdown.propTypes = {
  toggle: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
  content: PropTypes.oneOfType([PropTypes.string, PropTypes.element])
    .isRequired,
};

export default Dropdown;

使用它:

const dropDownToggle = (
  <button type="button">
    Dropdown
  </button>
);
const dropDownContent = 'content';

<DropDown
  toggle={dropDownToggle}
  content={dropDownContent}
/>

标签: javascripthtmlreactjs

解决方案


对于诸如切换内容之类的东西,您可以使用composition而不是inheritance传递数据。

以Facebook为例

这是通过props.children财产完成的。

function Dialog(props) {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        {props.title}
      </h1>
      <p className="Dialog-message">
        {props.message}
      </p>
      {props.children}
    </FancyBorder>
  );
}

class SignUpDialog extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.handleSignUp = this.handleSignUp.bind(this);
    this.state = {login: ''};
  }

  render() {
    return (
      <Dialog title="Mars Exploration Program"
              message="How should we refer to you?">
        <input value={this.state.login}
               onChange={this.handleChange} />

        <button onClick={this.handleSignUp}>
          Sign Me Up!
        </button>
      </Dialog>
    );
  }

  handleChange(e) {
    this.setState({login: e.target.value});
  }

  handleSignUp() {
    alert(`Welcome aboard, ${this.state.login}!`);
  }
}

render()我正在渲染Dialog组件并传递道具。props.children和自定义 propstitle, message 这让我们可以将子元素直接传递到输出中,我们甚至可以添加来自其他类的组件,就像我对SignUpDialog.


推荐阅读