React: How to render components based on MenuItem clicked? - reactjs

Below is the code:
import React from 'react';
import { Layout, Menu, Breadcrumb } from 'antd';
import { UserOutlined, ProfileFilled, CreditCardFilled, SearchOutlined, BankOutlined} from '#ant-design/icons';
const { SubMenu } = Menu;
const { Header, Content, Sider, Footer } = Layout;
function Admin(){
function handleClick(){
console.log("Search")
}
return(
<Layout>
<Header className="header">
<div className="logo" />
<Menu theme="light" mode="horizontal" defaultSelectedKeys={['2']} icon={<UserOutlined />}>
<Menu.Item key="1">Creame Cookies</Menu.Item>
</Menu>
</Header>
<Layout>
<Sider width={200} className="site-layout-background">
<Menu
theme="dark"
mode="inline"
defaultOpenKeys={['Dashboard']}
defaultSelectedKeys={['Dashboard']}
style={{ height: '250%', borderRight: 0, width: 250 }}
>
<Menu.Item key="Dashboard" icon={<UserOutlined />}>
Dashboard
</Menu.Item>
<Menu.Item onClick={handleClick} key="Search" icon={<SearchOutlined />}>
Search
</Menu.Item>
<SubMenu key="Profiles" icon={<ProfileFilled />} title="Profiles">
<Menu.Item key="1">Free Profiles</Menu.Item>
<Menu.Item key="2">Premium Profiles</Menu.Item>
</SubMenu>
<Menu.Item key="Payments" icon={<CreditCardFilled />}>
Payments
</Menu.Item>
</Menu>
</Sider>
<Layout style={{ padding: '0 72px 72px' }}>
<Content
className="site-layout-background"
style={{
padding: 24,
margin: 0,
minHeight: 500,
}}
>
<h1>Default</h1>
</Content>
</Layout>
</Layout>
{/*<Footer style={{ textAlign: 'center' }}>Creame Cookies Ltd</Footer> */}
</Layout>
)
}
export default Admin
Now, I need to render components at the location of the h1 tag with text as Default, based on the menuitem clicked. I am unsure of how to do this in react since I am new to it and feeling it difficult as compared to vannila javascript and jQuery in which I have already worked.

<h1>{someCondition ? 'Text A': 'Text B'}</h1> is generally how you handle this. You can always do the condition at the top of the component before your return statement if you prefer.
{ } is syntax to wrap an expression in React. You could put a ternary or just a variable in there to render.
Could also do <h1>{someCondtion ? <ComponentA /> : <ComponentB />}</h1>.

Related

How to switch between tabs or navigation menu using dynamic routing in react js?

I am quite new to ReactJS and I am really stuck in the process of routing. There are n numbers of methods on routing and i am really confused where should i place the links and the routes and is there any need of mounting a component in this or not and if once i am able to get the data so is routing the efficient way to do it in a dynamic environment?
i have an existing templates of ant design!
Index.js
import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Router, Route, Link } from "react-router";
import { Layout, Menu, Breadcrumb, Icon } from "antd";
import Example from "./Components/allSubCount";
const { SubMenu } = Menu;
const { Header, Content, Sider } = Layout;
ReactDOM.render(
<Layout>
<Header className="header">
<div className="logo" />
<Menu
theme="dark"
mode="horizontal"
defaultSelectedKeys={["2"]}
style={{ lineHeight: "64px" }}
/>
</Header>
<Layout>
<Sider width={200} style={{ background: "#fff" }}>
<Menu
mode="inline"
defaultSelectedKeys={["1"]}
defaultOpenKeys={["sub1"]}
style={{ height: "100%", borderRight: 0 }}
>
<SubMenu
key="sub1"
title={
<span>
<Icon type="user" />
Dashboard
</span>
}
>
<Menu.Item key="1">Sub Graph</Menu.Item>
<Menu.Item key="2">Int Graph</Menu.Item>
<Menu.Item key="3">PO Graph</Menu.Item>
</SubMenu>
<Menu.Item key="4">
<span>
<Icon type="user" />
Marketers
</span>
</Menu.Item>
<Menu.Item key="5">
<span>
<Icon type="user" />
Consultants
</span>
</Menu.Item>
</Menu>
</Sider>
<Layout style={{ padding: "0 24px 24px" }}>
<Content
style={{
background: "#fff",
padding: 24,
margin: 24,
minHeight: 280
}}
>
<Example />
</Content>
</Layout>
</Layout>
</Layout>,
document.getElementById("container")
);
Refer dis answer
https://stackoverflow.com/a/56053141/6150566
I have included sample code in the link that was provided in the above answer. However, you don't have to use protected routes if you don't prefer to. But it is better to isolate route and app layout logic.

Nested routes with react router v4 not working

I have create a route for a page.In side that page I have use 4 component.I have give path to these to these component.In header dropdown I have given links to these components, On first click the path is change.
but in second click the url is change but not redirecting.
const menu = (
<Dropmenu>
<Menu
key="menu"
style={{ backgroundColor: '#0f2037', borderRadius: '0' }}
>
<Menu.Item key="golive">
<Link to={'/s/live'} style={{ color: '#fff' }}>
<Icon type="video-camera" />
Start Live Broadcast
</Link>
</Menu.Item>
<Menu.Item key="mychannel" style={{ color: '#fff' }}>
<Link to={'/s/profile'} style={{ color: '#fff' }}>
<Icon type="user" />
Manage Profile
</Link>
</Menu.Item>
<Menu.Item key="settings">
<Link to={'/s/account'} style={{ color: '#fff' }}>
<Icon type="setting" />
Account
</Link>
</Menu.Item>
<Menu.Item
key="logout"
onClick={this.logoutCall}
style={{ color: '#fff' }}
>
<Icon type="logout" />
Logout
</Menu.Item>
</Menu>
</Dropmenu>
);
<BrowserRouter>
<Switch>
<Route path="/s" component={GoLive} />
<Route
path="/s/profile"
render={() => (
<div>
<ManageProfile descri={teprop} />
</div>
)}
/>
</Switch>
</BrowserRouter>
Adding exact to Routes will solve the problem:
<Route path="/s" exact={true} component={GoLive} />
<Route
exact={true}
path="/s/profile"
render={() => (
<div>
<ManageProfile descri={teprop} />
</div>
)}
/>
The Switch component renders the first matching route and /s is matched in /s/profile/ .
You can use exact in Route:
<Route exact path="/one" component={About}/>
https://reacttraining.com/react-router/web/api/Route/exact-bool

How to change Content based on Menu Item click in AntD (React UI Library)

I am following AntD Menu tutorial from here and it shows how to use this component. But I am failed to understand that how to change my Content when I click on different menu option. Tried searching a lot but did not find any useful help.
import { Layout, Menu, Icon } from 'antd';
const { Header, Sider, Content } = Layout;
class SiderDemo extends React.Component {
state = {
collapsed: false,
};
toggle = () => {
this.setState({
collapsed: !this.state.collapsed,
});
}
render() {
return (
<Layout>
<Sider
trigger={null}
collapsible
collapsed={this.state.collapsed}
>
<div className="logo" />
<Menu theme="dark" mode="inline" defaultSelectedKeys={['1']}>
<Menu.Item key="1">
<Icon type="user" />
<span>nav 1</span>
</Menu.Item>
<Menu.Item key="2">
<Icon type="video-camera" />
<span>nav 2</span>
</Menu.Item>
<Menu.Item key="3">
<Icon type="upload" />
<span>nav 3</span>
</Menu.Item>
</Menu>
</Sider>
<Layout>
<Header style={{ background: '#fff', padding: 0 }}>
<Icon
className="trigger"
type={this.state.collapsed ? 'menu-unfold' : 'menu-fold'}
onClick={this.toggle}
/>
</Header>
<Content style={{ margin: '24px 16px', padding: 24, background: '#fff', minHeight: 280 }}>
Some Conent
</Content>
</Layout>
</Layout>
);
}
}
ReactDOM.render(<SiderDemo />, mountNode);
Can you pls help.
Just WRAP your Layout tag inside Router tag of react-router-dom.
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import { Layout, Menu, Icon } from 'antd';
import Dashboard from './containers/Dashboard/Dashboard';
import Meseros from './containers/Meseros/Meseros';
const { Header, Content, Footer, Sider } = Layout;
const SubMenu = Menu.SubMenu;
class RouterApp extends Component {
state = {
collapsed: false,
};
onCollapse = (collapsed) => {
this.setState({ collapsed });
}
toggle = () => {
this.setState({
collapsed: !this.state.collapsed,
});
}
render() {
return (
<Router>
<Layout style={{ minHeight: '100vh' }}>
<Sider
collapsible
collapsed={this.state.collapsed}
onCollapse={this.onCollapse}>
<div className="logo" />
<Menu theme="dark" defaultSelectedKeys={['1']} mode="inline">
<Menu.Item key="1">
<Icon type="pie-chart" />
<span>Deshboard</span>
<Link to="/" />
</Menu.Item>
<Menu.Item key="2">
<Icon type="desktop" />
<span>Meseros</span>
<Link to="/meseros" />
</Menu.Item>
</Menu>
</Sider>
<Layout>
<Header style={{ background: '#fff', padding: 0, paddingLeft: 16 }}>
<Icon
className="trigger"
type={this.state.collapsed ? 'menu-unfold' : 'menu-fold'}
style={{ cursor: 'pointer' }}
onClick={this.toggle}
/>
</Header>
<Content style={{ margin: '24px 16px', padding: 24, background: '#fff', minHeight: 280 }}>
<Route exact path="/" component={Dashboard} />
<Route path="/meseros" component={Meseros} />
</Content>
</Layout>
</Layout>
</Router>
);
}
}
export default RouterApp;
If you don't want to change the route every time you choose a menu item you can use the following approach
function MyComponent(){
const [selectedMenuItem, setSelectedMenuItem]= useState('item1');
const componentsSwtich = (key) => {
switch (key) {
case 'item1':
return (<h1>item1</h1>);
case 'item2':
return (<h1>item2</h1>);
case 'item3':
return (<h3>item3/h3>);
default:
break;
}
};
return(
<div>
<Menu selectedKeys={selectedMenuItem} mode="horizontal" onClick={(e) =>
setSelectedMenuItem(e.key)}>
<Menu.Item key="item1">your first component here</Menu.Item>
<Menu.Item key="item2">your second here</Menu.Item>
<Menu.Item key="item3">your third here</Menu.Item>
</Menu>
<div>
{componentsSwitch(selectedMenuItem)}
</div>
</div>)
You can bind onClick with your MenuItem and re render the component upon clicking any menuItem. And you can make you content in your Constant.js or initialize it in your component state.
Add onClick method
<Menu.Item
key="1"
onClick={this.handleMenuClick}
>
<Icon type="user" />
<span>nav 1</span>
</Menu.Item>
make a handle for MenuItem click:
handleMenuClick = event => {
//you can get here event.target.value
//filter the content
//setState the content your component will re render and content will be updated.
}
In case you want to change the route, there is a working example here
https://codesandbox.io/embed/fervent-thunder-egyk1?fontsize=14&hidenavigation=1&theme=dark
Add Link component in Menu.Item and wrap with BrowserRouter from react-router-dom
<Menu.Item key="2">
CI/CD Pipelines
<Link to={`${match.url}/cicd`} />
</Menu.Item>
You can add the onClick prop for the Menu item as follow:
NB. I am using NextJs router to link the menus to their own corresponding page. In case you are using React, use Link from router-dom.
<pre>
<Menu
onClick={({ keyPath }) => router.push(`/${keyPath}`)}
mode="inline"
defaultSelectedKeys={["dashboard"]}
defaultOpenKeys={["company-info"]}
items={navs}
theme="dark"
/>

Semantic-UI-react fixed sidebar

Have Googled, searched within semantic ui's docs and issues page, and searched within stackoverflow. Couldn't find the answer.
Within Semantic-ui-react, how do I make a sidebar whose content is fixed to the screen? What I currently have is this:
<Sidebar.Pushable as={Segment}>
<Sidebar
id="sidebar"
as={Menu}
animation="overlay"
direction="right"
visible={this.state.visible}
vertical
inverted
>
{this.getMenuItems()}
</Sidebar>
<Sidebar.Pusher>
<Route path="/" component={Filler} />
</Sidebar.Pusher>
</Sidebar.Pushable>
There doesn't seem to be any word in it in the semantic-ui-react documentation, and making Sidebar.Pushable, Sidebar, or any of the Menu Items position:fixed; doesn't seem to work either.
I was able to achieve a sticky sidebar with the help of this answer.
Basically, it states that in order to have a fixed sidebar that sticks to the our infinite scrolling page, we must remove the transform attribute
on the parent container. The reasoning is because the transform changes the positioning context from the viewport to the
rotated element. As a result, the "fixed" child element, behaves as if it has "absolute" positioning.
I added this to the sidebar.overrides file
/* Page Context */
.pushable:not(body) {
transform: none;
}
.pushable:not(body) > .ui.sidebar,
.pushable:not(body) > .fixed,
.pushable:not(body) > .pusher:after {
position: fixed;
}
This solution is meant for the base semantic-ui library. Since semantic-ui-react requires semantic-ui, this ends up working for semantic-ui-react sidebars as well.
Give a try with below code.
<Sidebar as={Menu} animation='overlay' icon='labeled' inverted vertical visible width='wide'>
<Menu.Item as={Link} to="/admin">
<Icon name='building' />
Rubykraft
</Menu.Item>
<Menu.Item as='a'>
<Icon name='user' />
Shan
</Menu.Item>
<Menu.Item as='a'>
<Icon name='user' />
Vishnu
</Menu.Item>
</Sidebar>
I've used classes from semantic-ui's Sidebar module to create the desired fixed sidebar. If you want a more Component(ish) code, you should replace the pusher class with it's correspondent Sidebar.Pusher Component.
Here's my code:
import React, { Component } from 'react'
import { Dropdown, Icon, Input, Menu } from 'semantic-ui-react'
export default class MySidebar extends Component {
state = {}
handleItemClick = (e, { name }) => this.setState({ activeItem: name })
componentDidMount() {}
render() {
const { activeItem } = this.state
return(
<div className='pusher'>
<div className='full height'>
<div className='toc'>
<Menu className='inverted vertical left fixed'>
<Menu.Item>
Home
<Icon name='dashboard' />
<Menu.Menu>
<Menu.Item name='search' active={activeItem === 'search'} onClick={this.handleItemClick}>
Search
</Menu.Item>
<Menu.Item name='add' active={activeItem === 'add'} onClick={this.handleItemClick}>
Add
</Menu.Item>
<Menu.Item name='about' active={activeItem === 'about'} onClick={this.handleItemClick}>
Remove
</Menu.Item>
</Menu.Menu>
</Menu.Item>
<Menu.Item name='browse' active={activeItem === 'browse'} onClick={this.handleItemClick}>
<Icon name='grid layout' />
Browse
</Menu.Item>
<Menu.Item name='messages' active={activeItem === 'messages'} onClick={this.handleItemClick}>
Messages
</Menu.Item>
<Dropdown item text='More'>
<Dropdown.Menu>
<Dropdown.Item icon='edit' text='Edit Profile' />
<Dropdown.Item icon='globe' text='Choose Language' />
<Dropdown.Item icon='settings' text='Account Settings' />
</Dropdown.Menu>
</Dropdown>
</Menu>
</div>
<div className='article'>
<div>Content</div>
</div>
</div>
</div>
)
}
}
And the style:
.toc {
width: 200px;
}
.article {
margin-left: 210px;
}
Everything is easier!
<Sidebar.Pusher style={{overflow: 'scroll', height: '100%'}}>
I think you yourself will understand why this works.
You would need to manually do it with some CSS/SCSS. Basically, you need to set the height to a fixed value.
#media only screen and (max-width: 768px) {
.ui.wide.left.sidebar, .ui.wide.right.sidebar {
height: 100vh !important;
position: absolute;
}
.pusher {
margin-left: 20px;
}
}
.pushable {
min-height: 100vh;
}
.ui.wide.left.sidebar, .ui.wide.right.sidebar {
height: 100vh;
position: fixed !important;
bottom: 0px !important;
top: 0px !important;
}
Based on the Semantic React documentation, there's an obvious way to do this, but the behavior it produces is extremely wonky: the desktop sidebar menu sticks to the top of the window as expected until you scroll near the bottom, then zooms down and attaches to the BOTTOM of the screen.
Pretty awful. This appears to be a solid fix. I've only tested it in my own setup, but it should be fairly universal, or at least a good starting point!
In order to get the sticky sidebar/mobile overlay combo described above, you would expect the relevant part of your _app.jsx to look something like this. NOT THE ONLY WAY! But also not the point, adapt to your own situation. For clarity, anything below prefixed with my... is your responsibility.
// _app.jsx
<Sidebar.Pushable>
<Sticky>
<Sidebar
as={Menu}
animation="overlay"
direction="left"
inverted
onClick={myOnHideSidebar}
onHide={myOnHideSidebar}
size="huge"
vertical
visible={mySidebarVisible}
>
<MySidebarItems />
</Sidebar>
</Sticky>
<Sidebar.Pusher dimmed={mySidebarVisible}>
<Container>
<MyPageHeader />
<Grid>
<Grid.Row>
<Grid.Column computer={4} only="computer">
<Menu fluid size="huge" vertical>
<MySidebarItems />
</Menu>
</Grid.Column>
<Grid.Column mobile={16} tablet={16} computer={12}>
<Component {...pageProps} />
</Grid.Column>
</Grid.Row>
</Grid>
<MyPageFooter />
</Container>
</Sidebar.Pusher>
</Sidebar.Pushable>
In practice, this produces the weird behavior I described above.
Here's the fix. Look for the STICKYFIX comments, and note the stylesheet entry, which is necessary because of the -webkit style.
// _app.jsx
<Sidebar.Pushable style={{ transform: 'none' }}> // STICKYFIX
<Sticky>
<Sidebar
as={Menu}
animation="overlay"
direction="left"
inverted
onClick={myOnHideSidebar}
onHide={myOnHideSidebar}
size="huge"
vertical
visible={mySidebarVisible}
>
<MySidebarItems />
</Sidebar>
</Sticky>
<Sidebar.Pusher
dimmed={mySidebarVisible}
style={{ minHeight: '100vh' }} // STICKYFIX
>
<Container>
<MyPageHeader />
<Grid>
<Grid.Row>
<Grid.Column computer={4} only="computer">
<Menu className="sidebar-menu" fluid size="huge" vertical> // STICKYFIX
<SidebarItems />
</Menu>
</Grid.Column>
<Grid.Column mobile={16} tablet={16} computer={12}>
<Component {...pageProps} />
</Grid.Column>
</Grid.Row>
</Grid>
<MyPageFooter />
</Container>
</Sidebar.Pusher>
</Sidebar.Pushable>
// styles.css
.sidebar-menu {
position: sticky;
position: -webkit-sticky;
top: 20px;
}
Here's my gist detailing the fix.

How to make a Drawer like in Google Inbox with Material-UI

I'm building an app with Meteor, React and Material-UI. I have a custom left nav component based on Drawer.
class LeftNav extends Component {
constructor(props){
super(props);
}
render() {
return (
<Drawer open={this.props.open}
docked={false}
onRequestChange={this.props.handleOnRequestChange}
>
<Card >
<CardMedia overlay={<div><Avatar src='avatar.png' size={50} style={styles.avatar} /> <CardTitle title="Phil Cruz" subtitle="phil#philcruz.com" titleColor={darkWhite} subtitleColor={lightWhite}/></div>} >
<img src="/left_nav_wallpaper.jpg" />
</CardMedia>
</Card>
<MenuItem primaryText="testdomain1.com" leftIcon={<ActionGrade />} />
<MenuItem primaryText="testdomain2.com" leftIcon={<ActionHttp />}/>
<MenuItem primaryText="Add site..." leftIcon={<ContentAdd />} />
<Divider />
<MenuItem primaryText="Settings" leftIcon={<Settings />} />
<MenuItem primaryText="Help & About" leftIcon={<HelpOutline />} />
</Drawer>
);
}
};
I want to make it so it behaves like the Google InBox left nav/drawer. It has 3 sections: The top with the cover image and avatar, middle section and the bottom section.
I want the same behavior where:
the bottom menu items are fixed to the bottom (in red in the below
image)
the top section can scroll
How can I do that?
By reading these questions/answers:
How to create a sticky footer inside the LeftNav?
Get viewport/window height in ReactJS
Reactjs - Rerender on browser resize
I was able to come up with a solution. Basically, you need to put the content in 2 divs. Use absolute positioning in the bottom div to make it fixed to the bottom. You then need to calculate the height of the top div based on the height of the window minus the height of the footer div. Listen to the resize window event so you can update the div height manually as the browser is resized.
Here's the code:
class LeftNav extends Component {
constructor(props){
super(props);
this.state = { };
this.updateDimensions = this.updateDimensions.bind(this);
}
componentDidMount(){
this.updateDimensions();
window.addEventListener("resize", this.updateDimensions);
}
updateDimensions() {
this.setState({
height: window.innerHeight,
footerHeight: document.getElementById('leftNavFooter').clientHeight
});
}
render() {
return (
<Drawer open={this.props.open}
docked={false}
onRequestChange={this.props.handleOnRequestChange}
>
<div style={{overflowY: 'auto', overflowX: 'hidden', height: (this.state.height - this.state.footerHeight) + 'px'}}>
<Card >
<CardMedia overlay={<div><Avatar src='avatar.png' size={50} style={{ marginLeft: 16 }} /> <CardTitle title="Phil Cruz" subtitle="phil#philcruz.com" titleColor={darkWhite} subtitleColor={lightWhite}/></div>} >
<img src="/left_nav_wallpaper.jpg" />
</CardMedia>
</Card>
<Menu>
<MenuItem primaryText="testdomain1.com" leftIcon={<ActionGrade />} />
<MenuItem primaryText="testdomain2.com" leftIcon={<ActionHttp />}/>
<MenuItem primaryText="Add site..." leftIcon={<ContentAdd />} />
</Menu>
</div>
<div id="leftNavFooter" style={{position: 'absolute', bottom: 0, width: '100%', overflow: 'hidden'}}>
<Divider />
<Menu>
<MenuItem primaryText="Settings" leftIcon={<Settings />} />
<MenuItem primaryText="Help & About" leftIcon={<HelpOutline />} />
</Menu>
</div>
</Drawer>
);
}
};

Resources