React hidden navigation menu - javascript

I am working with ReactJS at the moment (I am very much a beginner). What I wanting to do is show/hide a menu component when a link is clicked in the site navigation. The menu is being built as a component that sits within a component (header).
The user clicks the menu button and that then toggles the menu to be shown or hidden, I am however having problems working out where the logic to show and hide the menu component should live the showing an hiding is relatively simple I basically want to add and remove a class to the menu component to show or hide it.
I have a similar show/hide working for my login and register forms, but the show and hide classes for these are added in the header component not the child component, here is my header component JS so far.
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Menu from './menu';
import LoginForm from '../Login';
import RegisterForm from '../Register';
export default class Explore extends Component {
constructor(props) {
super(props);
this.state = {
loginMenuVisible : false,
registerMenuVisible : false,
mainMenuVisible : false
};
console.log(this.state);
//this.triggerMenu = this.triggerMenu.bind(this);
}
render() {
return (
<div className="site__navigation">
<Menu />
<header className="site__header">
<img src="img/logo-full-color.png" alt="meatFree" />
<ul className="header__navigation">
<li className="header__navigation__item">
<a href="/register" onClick={this.toggleMenu.bind(this, 'register')}>Register</a>
<ul className={this.state.registerMenuVisible ? "dropdown visible" : "dropdown"}>
<li>
<LoginForm />
</li>
</ul>
</li>
<li className="header__navigation__item">
<a href="#" onClick={this.toggleMenu.bind(this, 'login')}>Login</a>
<ul className={this.state.loginMenuVisible ? "dropdown visible" : "dropdown"}>
<li>
<LoginForm />
</li>
</ul>
</li>
<li className="header__navigation__item">
<a href="" className="nav__toggle">
Menu
</a>
</li>
</ul>
</header>
</div>
);
}
toggleMenu(type, e) {
e.preventDefault();
console.log(type);
switch(type) {
case 'login':
if(this.state.loginMenuVisible) {
this.setState({loginMenuVisible : false});
} else {
this.setState({
registerMenuVisible : false,
loginMenuVisible : true
});
}
break;
case 'register':
if(this.state.registerMenuVisible) {
this.setState({registerMenu : false});
} else {
this.setState({
registerMenuVisible : true
});
}
break;
case 'menu':
this.setState({mainMenuVisible : true });
}
}
}
AS you see I have a element in the state called mainMenuVisible, I want to be able to maniuplate this within the Menu component.

I like to keep things simple:
export default class Example extends Component {
constructor(){
super(props)
this.state = {
showMenu: false
}
this.menuShowToggle = this.menuShowToggle.bind(this);
}
menuShowToggle = () => {
this.setState({showMenu: !this.state.showMenu})
}
render = () => {
return (
<div>
<div className={this.state.showMenu ? 'showMenu': 'hideMenu'}>Hidden Menu</div>
<button type="button" onClick={this.menuShowToggle} value="toggle" />
</div>
)
}
}

To achieve this using your current setup, you could pass the toggleMenu() function as a prop to your rendered Menu component
<Menu toggleMenu={this.toggleMenu} />
Then within the Menu component, you could call toggleMenu() in a click handler and pass in 'menu' as the type.

If you are using ReactJs you should consider the following pattern:
1. Set a state specifically to show/hide the the menu
2. Create a function which will toggle the state
3. Add a conditional rendering for the component menu
Here is how the the code can be done:
Step 1.
constructor(props) {
super(props);
this.state = {
isComponenetMenuVisisble : false, // by default to disable it
};
}
Step 2.
toggleComponentMenu = () => {
const isComponenetMenuVisisble = !this.state.isComponenetMenuVisisble;
this.setState({ isComponenetMenuVisisble });
}
Step 3.
{this.state.isComponenetMenuVisisble && <Menu />}
// if isComponenetMenuVisisble is true render <Menu />
And then you can add the event handler like the following
<div className="your-element" onClick={this.toggleComponentMenu}>
... your stuff
</div>
A good point to highlight in the code above is that I am using a method rather than a function in step 2. When using a method instead of a function there will be no need to bind the function on event handlers because this context will be the class itself. Much more details can be found about this in here http://blog.andrewray.me/react-es6-autobinding-and-createclass/

Related

How to switch classes onClick

thank you for reading this. I am attempting to learn React by making a dummy website, however I've run into a roadblock.
I want the "display-page" div to only show the Send element initially (which is easy) but when someone clicks one of the 4 options from the content_bar div I want remove the current element and only show the newly clicked element (in this case it is 'Transactions')
I've read about useState and routing but I'm not sure how to implement
Thanks! Please let me know if I didnt give enough details
import React, { Component } from 'react';
import './Data.css';
import Transactions from './Transactions';
import Send from './Send';
class Data extends Component {
constructor(props) {
super(props);
this.state = {
content: <Send />
}
}
transactionpage = () => {
this.setState({content: <Transactions/>});
}
render() {
return(
<div className="content">
<div className="content_bar">
<h5>Send</h5>
<h5 onClick={this.transactionpage}>Transactions</h5>
<h5>Friends</h5>
<h5>Professional</h5>
</div>
<div className="display-page">
{this.state.content}
</div>
</div>
);
}
}
export default Data;
Looking at You can't press an <h5> tag and React code without state feels strange.
You need to learn more to achieve your goal, these are the topics:
JSX expresssion
Conditional rendering
State management
Let me show you my solution, it is one of many ways.
class Data extends Component {
constructor(props) {
super(props);
this.state = {
toDisplay: ''
};
this.changeToDisplay = this.changeToDisplay.bind(this);
}
changeToDisplay(e) {
this.setState({ toDisplay: e.target.textContent.toString() });
}
render() {
return (
<div className="content">
<div className="content_bar">
<button onClick={e => changeToDisplay(e)}>Send</button> <br />
<button onClick={e => changeToDisplay(e)}>Transactions</button> <br />
<button>Friends</button> <br />
<button>Professional</button> <br />
</div>
<div className="display-page">
{this.state.toDisplay === 'Send' ? <Send /> : null}
{this.state.toDisplay === 'Transactions' ? <Transactions /> : null}
</div>
</div>
);
}
}

React: animationOut not showing using Animated.css

I have an example of a toggle that hide/display content.
I used https://www.npmjs.com/package/react-animated-css and it worked perfectly when displaying the content, meaning that after showing the content the animation is playing.
Now that I press the toggle button, the content instantly vanishes without animation.
I checked in the console and the class for the animationOut is working, but it seems that the content closes before the animation have the time to play, so it's hidden.
How to fix this issue ?
The working code : https://stackblitz.com/edit/react-sorgz5?file=src/App.js
import React, { Component } from "react";
import ContentComponent from "./content.js";
import { Animated } from "react-animated-css";
export default class toggleComponent extends React.Component {
constructor() {
super();
this.state = {
isShowBody: false
};
}
handleClick = event => {
this.setState({ isShowBody: !this.state.isShowBody });
};
checkbox = () => {
return (
<div>
<span className="switch switch-sm">
<label>
<input
type="checkbox"
name="select"
onClick={this.handleClick.bind(this)}
/>
<span />
</label>
</span>
</div>
);
};
render() {
return (
<div>
{this.checkbox()}
<Animated
animationIn="bounceInLeft"
animationOut="fadeOut"
isVisible={this.state.isShowBody}
>
<div>{this.state.isShowBody && <ContentComponent />}</div>
</Animated>
</div>
);
}
}
Solved. I needed to remove this.state.isShowBody in <div>so the condition of the visibility is controller by isVisible.
<Animated
animationIn="bounceInLeft"
animationOut="fadeOut"
isVisible={this.state.isShowBody}
>
<div>{<ContentComponent />}</div>
</Animated>

how to implement tabs in react with using any library?

could you please tell me how to implement tabs in react with using any library ?
I follow this link and tried to make tabs
https://toddmotto.com/creating-a-tabs-component-with-react/
but not succeeded.
Here is my code:
https://codesandbox.io/s/D9Q6qWPEn
import React, {Component} from 'react';
class Tabs extends Component {
constructor() {
super();
this.state= {
selected:0
}
}
_renderContent() {
return (
<div className="tabs__content">
{this.props.children[this.state.selected]}
</div>
);
}
render() {
return (
<div className="tabs">
{this._renderContent()}
</div>
)
}
}
export default Tabs;
I am not able to show tabs and it there individual contents after click
any update ?
If I understand your problem correctly, you just want to display labels for your tabs.
You can do this in many ways in React but without changing your code too much, you can accomplish this task by changing render() method of Tabs component, like below:
setTab(index) {
this.setState({
selected: index,
});
}
_renderLabels() {
return this.props.children.map((child, index) => (
<div key={child.props.label} onClick={() => { this.setTab(index) }}>
{child.props.label}
</div>
));
}
render() {
return (
<div className="tabs">
{this._renderLabels()}
{this._renderContent()}
</div>
);
}
What we do here is basically rendering labels based on props.children. For each label we append click handler.
You could improve this code by creating specific components like TabPane, TabLabel.
Full code of Tabs component.
import React, { Component } from "react";
class Tabs extends Component {
constructor() {
super();
this.state = {
selected: 0
};
}
setTab(index) {
this.setState({
selected: index,
});
}
_renderContent() {
return (
<div className="tabs__content">
{this.props.children[this.state.selected]}
</div>
);
}
_renderLabels() {
return this.props.children.map((child, index) => (
<div key={child.props.label} onClick={() => { this.setTab(index) }}>
{child.props.label}
</div>
));
}
render() {
return (
<div className="tabs">
{this._renderLabels()}
{this._renderContent()}
</div>
);
}
}
export default Tabs;
Demo: https://codesandbox.io/s/pRvG6K0r
I implemented this and is working awesome:
I'm using a functional component with Hooks.
const Tabs = () => {
const [currentTab, setCurrentTab] = useState('first-tab');
const toggleTab = () => {
switch (currentTab) {
case 'first-tab':
return <FirstTab />;
case 'second-tab':
return <SecondTab />;
default:
return null;
}
};
return (
<div>
<div>
<h3 onClick={() => setCurrentTab('first-tab')}>First Tab</h3>
<h3 onClick={() => setCurrentTab('second-tab')}>Second Tab</h3>
</div>
{toggleTab()}
</div>
);
};
You can add more components if you want.
Psdt: And if you want to add styles to the Current Tab Title you can create another useState Hook, something like "isActive" and this set it up on the tag classes.
const Tabs = () => {
const tabsData = [
{ id: 0, tabName: "first tab", tabData: "first tab data" },
{ id: 1, tabName: "second tab", tabData: "second tab data" },
{ id: 2, tabName: "third tab", tabData: "third tab data" },
];
const [activeIndex, setActiveIndex] = useState(false);
const tabClick = (index) => {
setActiveIndex(index);
};
return (
<>
<ul>
{tabsData.map((tab) => {
return (
<li key={tab.id} onClick={() => tabClick(tab.id)}>
{tab.tabName}
</li>
);
})}
</ul>
<ul>
{tabsData.map((tab) => {
if (tab.id === activeIndex) {
return <li key={tab.id}>{tab.tabData}</li>;
}
})}
</ul>
</>
);
};
if all you have is a hammer, everything looks like a nail
Don't try to use React for everything. Not only is this a bad practice. React was never intended to fit that purpose. Creating tabs is 90% CSS and only 10% JS (controlling which one gets the "active" state.
I created an example that implements tabs 100% using CSS, It doesn't work well since only after a tab is clicked the content is shown, there is no default.
If you wanted to automate this (e.g.) in an React component The only thing you have to do is bind a tab click to an active state a classname representing the active state (e.g.: tab--active). And create a default.
.tabs__list-item {
display: inline;
}
.tab {
display: none;
}
.tab:target { /* Only works if tab is clicked, can be fixed with React. */
display: block;
}
<nav class="tabs">
<ul class="tabs__list">
<li class="tabs__list-item"><a class="tabs__link" href="#tab1">Tab 1</a></li>
<li class="tabs__list-item"><a class="tabs__link" href="#tab2">Tab 2</a></li>
<li class="tabs__list-item"><a class="tabs__link" href="#tab3">Tab 3</a></li>
</ul>
</nav>
<section class="tab" id="tab1">
<h1>Tab 1 header</h1>
<p>This is the content of tab 1.</p>
</section>
<section class="tab" id="tab2">
<h1>Tab 2 header</h1>
<p>This is the content of tab 2.</p>
</section>
<section class="tab" id="tab3">
<h1>Tab 3 header</h1>
<p>This is the content of tab 3.</p>
</section>
In short:
Write the HTML structure / CSS markup first
Observe missing logic
Implement missing logic using the best tool.
React may be a valid tool for this purpose but start by having React rendering your HTML and CSS. If you can't get the "wiring" logic to work open a question indicating what specific problem you encounter.

ReactJS. calling a function from an outside variable

I'm new to ReactJS and trying to make a small web application.
I have a list of items to put in a sidebar, and I want each item to give back a status tu the sidebar when clicked (so that I can style the active link accordingly).
import React, {Component} from 'react';
import SideBarItem from "./SideBarItem";
const items = {
'DASHBOARD' : 'home',
'Utenti': 'user',
'Corsi' : 'education',
'Logistica' : 'check',
'Comunicazioni': 'bullhorn'
};
const listItems = Object.entries(items).map(([key,value])=>{
return <SideBarItem
onClick={this.changeState(key)} active={this.state.active == key ? 'active' : ''}
title={key}
glyph={'glyphicon glyphicon-' + value.toString()}/>
});
class SideBar extends Component {
constructor(props) {
super(props);
this.state = {active: 'DASHBOARD'};
}
changeState (row) {
this.setState({
active: row
});
}
render() {
return (
<div id = "sidebar" className="col-sm-3 col-md-2 sidebar paper-depth-1">
<ul className = 'nav nav-sidebar'>
{listItems}
</ul>
</div>
);
}
}
export default SideBar;
But this code is returnig the following error:
TypeError: _this.changeState is not a function
I understand that there's something wrong in calling a component function from an outside variable, but I don't get how can I make this work in any other way.
If you create the list of items in render(), the this scope will be the component instance, as you need it to be.
class SideBar extends Component {
constructor(props) {
super(props);
this.state = {active: 'DASHBOARD'};
}
changeState(row) {
this.setState({
active: row
});
}
render() {
return (
<div id="sidebar" className="col-sm-3 col-md-2 sidebar paper-depth-1">
<ul className="nav nav-sidebar">
{Object.entries(items).map(([key,value]) =>
<SideBarItem
onClick={() => this.changeState(key)}
active={this.state.active == key ? 'active' : ''}
title={key}
glyph={'glyphicon glyphicon-' + value.toString()}
/>
)}
</ul>
</div>
);
}
}

React - How to show relative div when mouse hover on a html tag?

Below is my code...
<ul className="no-style board__list">
{Object.keys(today.books).map(function(id) {
var refBook = today.books[id][0];
return (
<li key={refBook._id} className="board__list-item">
<div className="container flexrow">
<div className="flexrow__fit-2">{refBook.book_no}</div>
<div className="flexrow__org">
<span className="board__icon-wrap">
{refBook.memo
? (<i className="fa fa-flag" style={{color:"#F9AB9F"}}></i>)
: null
}
</span>
{refBooking.memo
? (<div className="memo_dialog">{refBook.memo}</div>)
: null
}
</div>
</div>
</li>
);
})}
</ul>
I have a object books array and I create a fa-flag icon for each book.
What I want is to show different memo dialog when mouse hover on each flag icon.
I know how to do it with query but how can I do this in react way not using jquery?
I'm not sure what are you trying to achieve but this example might be useful for you
class Book extends React.Component {
constructor(props){
super(props);
this.handleOver = this.handleOver.bind(this);
}
handleOver(name){
this.props.over(this.props.name)
}
render(){
return <div onMouseOver={this.handleOver}>{this.props.name}</div>
}
}
class BookList extends React.Component {
constructor(props){
super(props);
this.mouseOver = this.mouseOver.bind(this);
this.state = {
books: ['hello', 'amazing', 'world'],
memo: ''
}
}
mouseOver(name){
this.setState({memo: name})
}
render(){
const bookList = this.state.books.map((book, index)=>{
return <Book key={index} name={book} over={this.mouseOver}/>
});
return <div>
{bookList}
<hr/>
<div>{this.state.memo}</div>
</div>
}
}
React.render(<BookList />, document.getElementById('container'));
Also fiddle example.
I hope it will help you. Thanks
I suggest you to use isHovered state variable, to store hover state.
We are displaying some component(in your case it would be dialog box), if isHovered is true and hide it when this variable is false.
When we will hover on link element, we will trigger handleEnter function to set isHovered variable to true.
Similarly, when we are moving cursor out of link element, we are triggering handleLeave function to set isHovered variable to false.
Example:
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
isHovered: false,
};
}
handleEnter() {
this.setState({
isHovered: true
});
}
handleLeave() {
this.setState({
isHovered: false
});
}
render() {
return (
<div>
<a
onMouseEnter={this.handleEnter.bind(this)}
onMouseLeave={this.handleLeave.bind(this)}
>Link</a>
{this.state.isHovered ? (
<div className="box">A component</div>
) : (
<div />
)}
</div>
);
}
}
Also, you can see demo at CodePen.

Categories

Resources