I am new to React.js, and I'm learning by converting a website made in vanilla javascript to a React.js application. However, I am having trouble replicating the drop-down menu functionalities on the navigation bar.
Each section is comprised of divs with an onClick that expands its contents vertically to be viewable by changing overflow
and height
css settings. However, there's a catch: Only one drop-down should be expanded at a time. I was able to do this in the regular JS site, but I would like use parent-child and sibling relationships between components in React to get the same effect in the new rendition.
With an onClick event, one tab of the bar should open and, if any other tabs are expanded, close them.
I tried to use info from the solutions to this question, but it's not in class-component form and deals with inputs rather than divs. In addition, most search results regarding this only concern vanilla js, not React.js.
At first I attempted keeping states in the parent component, but their asynchronous nature made it a struggle to update them at just the right time.
Here I have stripped down the other irrelevant components of the site and provided a replication of my issue.
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;
}
Expected result: When a tab on the nav bar is clicked, it expands and displays information below it. Clicking it again reverts the tab back to its original height and hides. Clicking another tab while one is currently open will close the old one and expand the new one.
Actual result: Currently they expand as expected, but they don't have a means of closing each other yet. It needs a structure in the parent to keep track of the drop-downs.