React.js父级和同级组件:一次仅扩展一个导航栏div

时间:2019-05-03 18:31:15

标签: javascript reactjs

我是React.js的新手,我正在通过将使用javascript制作的网站转换为React.js应用程序来学习。但是,我在复制导航栏上的下拉菜单功能时遇到麻烦。

每个部分均由具有onClick的div组成,该onClick可以通过更改overflowheight css设置垂直扩展其内容以使其可见。但是,有一个陷阱:一次只能扩展一个下拉菜单。我能够在常规的JS网站中做到这一点,但我想在React中使用组件之间的父子关系和同级关系在新版本中获得相同的效果。

使用onClick事件,应打开该栏的一个标签,如果展开了其他标签,则将其关闭。

我尝试将解决方案中的信息用于this question,但它不是类组件形式的,而是处理输入而不是div。此外,与此相关的大多数搜索结果仅涉及普通js,而不涉及React.js。

起初,我尝试将状态保留在父组件中,但是它们的异步特性使它很难在正确的时间更新它们。

在这里,我删除了网站的其他不相关部分,并提供了我的问题的副本。

index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import Tab from './Tab';
import './index.css';

class TabBar extends React.Component {
  constructor() {
    super();
    this.state = {
      //currently no states
    }
  }

  render() {
    return (
      <div className="tab_bar">
        <Tab name="Tab 1" />
        <Tab name="Tab 2" />
        <Tab name="Tab 3" />
      </div>
    )
  }
}

class Main extends React.Component {
  render() {
    return (
      <TabBar />
    )
  }
}
ReactDOM.render(<Main />, document.getElementById('root'));

Tab.js:

import React from 'react';

class TabHeader extends React.Component {
  constructor() {
    super();

  }
  render() {
    return (
      <div className="tab_header" onClick={this.props.onClick}>
        <h3>{this.props.name}</h3>
      </div>
    )
  }
}

class Tab extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      height: "7vh",
      overflow: "hidden"
    }
    this.changeTabHeight = this.changeTabHeight.bind(this);
  }

  changeTabHeight() {
    if (this.state.height === "7vh") {
      this.setState({
        height: "20vh",
        overflow: "unset"
      });
    } else {
      this.setState({
        height: "7vh",
        overflow: "hidden"
      });
    }
  }

  render() {
    return (
      <div className="tab_container" style={{overflow: this.state.overflow, height: this.state.height}}>
        <TabHeader name={this.props.name} onClick={this.changeTabHeight} />
        <div className="tab">
          <p>This is the tab content.</p>
        </div>
      </div>
    )
  }
}

export default Tab;

index.css:

.body, .root {
  width: 100%;
  height: 100%;
}

.tab_bar {
  width: 100%;
  height: 10%;
  display: flex;
}

.tab_container{
  height: 7vh;
  margin: 0;
  display: inline-block;
  background-color: #82d86c;
  border-left: 1px solid #99ff7f;
  -webkit-transition: height 0.5s;
  transition: height 0.5s;
  overflow: hidden;
}

.tab_header {
  display: flex;
  align-items: center;
  vertical-align: middle;
  height: 7vh;
  text-align: center;
  background-color: #99ff7f;
}

.tab_header h3 {
  margin: 0;
}

.tab {
  margin: 0;
  padding: 5px;
}

预期结果: 单击导航栏上的选项卡时,它将展开并在其下方显示信息。再次单击它可以将选项卡还原到其原始高度并隐藏。当前打开一个选项卡时,单击它会关闭旧的选项卡并展开新的选项卡。

实际结果: 目前,它们的扩张如预期的那样,但是它们还没有相互关闭的方法。它需要父级中的结构来跟踪下拉列表。

1 个答案:

答案 0 :(得分:1)

当前存在的问题是,您直接在Tab内部的子组件TabBar中处理状态。

按您期望的那样采用模块化方式。


index.js :我们可以通过创建一个Tab数组并遍历此选项卡来对其进行改进

import React from "react";
import ReactDOM from "react-dom";
import Tab from "./Tab";
import "./index.css";

class TabBar extends React.Component {
  constructor() {
    super();
    this.state = {
      selectedTab: null,
    };
    this.onSelectTab = this.onSelectTab.bind(this);
  }

  onSelectTab(tabIndex) {
    // In case the user clicks again on the tab, unselect it
    const selectedTab = this.state.selectedTab === tabIndex ? false : tabIndex;
    this.setState({ selectedTab });
  }

  render() {
    return (
      <div className="tab_bar">
        <Tab
          name="Tab 1"
          isSelected={this.state.selectedTab === 0}
          onClickTab={() => this.onSelectTab(0)}
        />
        <Tab
          name="Tab 2"
          isSelected={this.state.selectedTab === 1}
          onClickTab={() => this.onSelectTab(1)}
        />
        <Tab
          name="Tab 3"
          isSelected={this.state.selectedTab === 2}
          onClickTab={() => this.onSelectTab(2)}
        />
      </div>
    );
  }
}

class Main extends React.Component {
  render() {
    return <TabBar />;
  }
}
ReactDOM.render(<Main />, document.getElementById("root"));

Tab.js :请记住,拥有功能组件而不带状态是更好的方法。

import React from "react";

class TabHeader extends React.Component {
  constructor() {
    super();
  }
  render() {
    return (
      <div className="tab_header" onClick={this.props.onClickTab}>
        <h3>{this.props.name}</h3>
      </div>
    );
  }
}

class Tab extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    // Moved the style in the CSS rather than in function + state
    // The !!this.props.isSelected allow to always return false / true response
    return (
      <div className={ `tab_container is-selected-${!!this.props.isSelected}`}>
        <TabHeader name={this.props.name} onClickTab={this.props.onClickTab} />
        <div className="tab">
          <p>This is the tab content.</p>
        </div>
      </div>
    );
  }
}

export default Tab;

index.css :添加这两个类,因为最好在CSS中使用样式,而不是直接在组件内部使用

.is-selected-true {
  height: "20vh",
  overflow: "unset"
}


.is-selected-false {
  height: "7vh",
  overflow: "hidden"
}