How to add if else inside the Tabs in react bootstrap - reactjs

I try to execute following code but I got some error.
Error : ReactBootstrap: The Tab component is not meant to be rendered! It's an abstract component that is only valid as a direct Child of the Tabs Component. For custom tabs components use TabPane and TabsContainer directly.
import { Row, Col, Tabs, Tab } from "react-bootstrap";
import One from "../One.jsx";
//One,Two .. etc There are more
render(
<Tabs>
<Tab eventKey={1} title="Tab 1"><One/></Tab>
<Tab eventKey={2} title="Tab 2"><Two/></Tab>
<Tab eventKey={3} title="Tab 3"><Three/></Tab>
{this.state.type === type && (
<Tab eventKey={4} title="Tab 4"><Four/></Tab>
<Tab eventKey={5} title="Tab 5"><Five/></Tab>
<Tab eventKey={6} title="Tab 6"><Six/></Tab>
)}
</Tabs>
)

I found this solution by accident.
I used to declare component's name as Tab without import from 'react-bootstrap' and using JSX condition rendering not any problem
But when I changed component's name to another, I found error from 'react-bootstrap' and my JSX condition rendering didn't work anymore cause 'react-bootstrap' wont accept JSX shorthand fragment or any.
So I declare empty component for handle error and using <>...</> in JSX condition rendering and everything works for me.
import React from "react";
import { Tabs } from "react-bootstrap";
const Tab = () => {
return <></>;
};
export const App = (props) => {
return(
<Tabs>
<Tab eventKey={1} title="Tab 1"><One/></Tab>
<Tab eventKey={2} title="Tab 2"><Two/></Tab>
<Tab eventKey={3} title="Tab 3"><Three/></Tab>
{props.type === type && (
<>
<Tab eventKey={4} title="Tab 4"><Four/></Tab>
<Tab eventKey={5} title="Tab 5"><Five/></Tab>
<Tab eventKey={6} title="Tab 6"><Six/></Tab>
</>
)}
</Tabs>
)
}
On top is not good practice but it's easy to declare condition.
In case you want to do with better practice use this instead.
import React from "react";
import { Tabs, Tab } from "react-bootstrap";
export const App = (props) => {
return(
<Tabs>
<Tab eventKey={1} title="Tab 1"><One/></Tab>
<Tab eventKey={2} title="Tab 2"><Two/></Tab>
<Tab eventKey={3} title="Tab 3"><Three/></Tab>
{props.type === type && <Tab eventKey={4} title="Tab 4"><Four/></Tab>}
{props.type === type && <Tab eventKey={5} title="Tab 5"><Five/></Tab>}
{props.type === type && <Tab eventKey={6} title="Tab 6"><Six/></Tab>}
</Tabs>
)
}

I don't think you can construct new Tab components like that using conditional rendering. As stated in the error message, you can use Tab.Container & Tab.Pane to create your customs Tabs.
Reference to the docs:
For more complex layouts the flexible TabContainer, TabContent, and
TabPane components along with any style of Nav allow you to quickly
piece together your own Tabs component with additional markup needed.
Example implementation of Tabs contruction with conditional rendering:
return (
<Tab.Container defaultActiveKey={1}>
<Nav variant="pills" className="flex-column">
<Row>
<Nav.Item>
<Nav.Link eventKey={1}>Tab 1</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey={2}>Tab 2</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey={3}>Tab 2</Nav.Link>
</Nav.Item>
{this.state.type === type && (
<>
<Nav.Item>
<Nav.Link eventKey={4}>Tab 4</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey={5}>Tab 5</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey={6}>Tab 6</Nav.Link>
</Nav.Item>
</>
)}
</Row>
</Nav>
<Tab.Content>
<Tab.Pane eventKey={1} title="Tab 1">
1
</Tab.Pane>
<Tab.Pane eventKey={2} title="Tab 2">
2
</Tab.Pane>
<Tab.Pane eventKey={3} title="Tab 3">
3
</Tab.Pane>
{this.state.type === type && (
<>
<Tab.Pane eventKey={4} title="Tab 4">
4
</Tab.Pane>
<Tab.Pane eventKey={5} title="Tab 5">
5
</Tab.Pane>
<Tab.Pane eventKey={6} title="Tab 6">
6
</Tab.Pane>
</>
)}
</Tab.Content>
</Tab.Container>
);
In fact, if you view the components on React Dev Tools, you will notice that the "Tab" component in fact is not actually rendered when using Tabs & Tab combo - hence they defined it as "abstract" component
Alternatively, if you must use Tabs & Tab JSX combo, then you are going to have to implement the condition on the entire Tabs rendering - not just a section of it. You can find an example here: https://codesandbox.io/s/beautiful-pond-quc2b?file=/src/App.js

You can refer to the following official documentation. It is explained very well.
https://reactjs.org/docs/conditional-rendering.html
Here is a sample code which I took from documentation. Hope this will clear your concept.
render() {
const isLoggedIn = this.state.isLoggedIn;
let button;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}

Related

Placing a picture next to a title for a react bootstrap Tab

React bootstrap Tabs allow us to create tabs.
<Tabs defaultActiveKey="profile" id="uncontrolled-tab-example">
<Tab eventKey="home" title="Home">
<Sonnet />
</Tab>
<Tab eventKey="profile" title="Profile">
<Sonnet />
</Tab>
<Tab eventKey="contact" title="Contact" disabled>
<Sonnet />
</Tab>
</Tabs>
For each Tab there is a title tag that accepts a string. I wonder if it is possible to display a picture instead of the title? Or display both? Also, I wish I could display a picture next to the Tab's title.
see the first tab, you have a title and an image one next to each other.
<Tab.Container id="left-tabs-example" defaultActiveKey="first">
<Row>
<Col sm={3}>
<Nav variant="pills" className="flex-column">
<Nav.Item>
<Nav.Link eventKey="first">
Tab 1
<img src="https://lh3.googleusercontent.com/-pxzt5JSmq3o/AAAAAAAAAAI/AAAAAAAAARw/oSQ00wYMa9g/photo.jpg?sz=32"></img>
</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey="second">Tab 2</Nav.Link>
</Nav.Item>
</Nav>
</Col>
<Col sm={9}>
<Tab.Content>
<Tab.Pane eventKey="first">
<Sonnet />
</Tab.Pane>
<Tab.Pane eventKey="second">
<Sonnet />
</Tab.Pane>
</Tab.Content>
</Col>
</Row>
</Tab.Container>

Attempted import error: 'Sonnet' is not exported from 'react-bootstrap'

The React-Bootstrap code that I have used for ListGroups has a Component named "Sonnet" which perhaps has not been exported in the React-Bootstrap, due to which I am facing the 'Sonnet' is not exported from 'react-bootstrap' issue regardless of my attempts to even import it manually or import the complete React-bootstrap package with "*". I have not found a single thread or a blog which even lists "Sonnet" errors or anything for that matter. Need you guys to help me understand!
My attempts have been:
reinstalling bootstrap/
import {Sonnet} from 'react-bootstrap';/
import * as ReactBootstrap from 'react-bootstrap';
None seem to work
The sample for ref:
import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
//import './Assets/css/default.min.css';
//import * as ReactBootstrap from 'react-bootstrap';
import {Card,ListGroup,Tab,Row,Col,Sonnet} from 'react-bootstrap';
class Data extends React.Component {
render(){
return (
<data>
<div className="data">
<Tab.Container id="list-group-tabs-example" defaultActiveKey="#link1">
<Row>
<Col sm={4}>
<ListGroup>
<ListGroup.Item> Online Devices
</ListGroup.Item>
<ListGroup.Item action href="#link1">
Soil Sensor
</ListGroup.Item>
<ListGroup.Item action href="#link2">
Level Sensor
</ListGroup.Item>
</ListGroup>
</Col>
<Col sm={8}>
<Tab.Content>
<Tab.Pane eventKey="#link1">
<Sonnet/>
Soil sensor
</Tab.Pane>
<Tab.Pane eventKey="#link2">
<Sonnet/>
Level Sensor
</Tab.Pane>
</Tab.Content>
</Col>
</Row>
</Tab.Container>
</div>
</data>
);
}
}
export default Data;
I understand 'Sonnet' as just placeholder. Consider it as a dummy class. Instead of 'Sonnet', replace it with your own class. I will show you how I did.
This is original template from react-bootstrap document.
<Tab eventKey="home" title="Home">
<Sonnet />
</Tab>
<Tab eventKey="profile" title="Profile">
<Sonnet />
</Tab>
<Tab eventKey="contact" title="Contact" disabled>
<Sonnet />
</Tab>
If I apply this into my own project...
<Tab eventKey="home" title="Home">
<SignUp />
{/* <Sonnet /> */}
</Tab>
<Tab eventKey="profile" title="Profile">
<SignIn />
{/* <Sonnet /> */}
</Tab>
<Tab eventKey="contact" title="Contact" disabled>
{/* <Sonnet /> */}
</Tab>
</Tabs>
'SignUp' and 'SignIn' is my own react component.
You must replace "<Sonnet />" with your own class, that you want to render.
Yup, replace <Sonnet /> with your own class, that you want to render.
<Tabs defaultActiveKey="home" id="uncontrolled-tab-example">
<Tab eventKey="home" title="Home">
<TabContent />
{/* <Sonnet /> */}
</Tab>
<Tab eventKey="profile" title="Profile">
<TabContent />
{/* <Sonnet /> */}
</Tab>
<Tab eventKey="contact" title="Contact" disabled>
<TabContent />
{/* <Sonnet /> */}
</Tab>
</Tabs>

Add a image to React Bootstrap dropdown

I'm using React Bootstrap and React Router Bootstrap for my Navbar, and I am making a user profile dropdown menu list.
I'd like to be able to have an user's avatar show up in place of the 'title' property. (The same idea as the user profile dropdown on Github)
Is this possible? I don't see any options to use an image instead of title for NavDropdown
<Navbar inverse>
<Navbar.Header>
<Navbar.Toggle />
</Navbar.Header>
<Navbar.Collapse>
<Nav pullRight>
<NavDropdown eventKey={ 3 } id="profile-dropdown" >
<LinkContainer to="/profile/edit" >
<NavItem eventKey={ 3.4 } > Edit </NavItem>
</LinkContainer>
<LinkContainer to="/logout">
<Logout eventKey={ 3.5 } />
</LinkContainer>
</NavDropdown>
</Nav>
</Navbar.Collapse>
</Navbar>
Would a SplitButton or straight Dropdown be a better option? I don't really see much that the "NavDropdown" is adding to the HTML.
The NavDropdown's title property can take any React element as a value. This is what I did:
<Nav pullRight>
<NavDropdown eventKey={1}
title={
<div className="pull-left">
<img className="thumbnail-image"
src={src}
alt="user pic"
/>
{user.username}
</div>
}
id="basic-nav-dropdown">
<MenuItem eventKey={1.1} href="/profile">Profile</MenuItem>
<MenuItem divider />
<MenuItem eventKey={1.3}>
<i className="fa fa-sign-out"></i> Logout
</MenuItem>
</NavDropdown>
</Nav>
You'll probably need to adjust the css a little bit.
You can also use the <Image /> component, e.g.
const UserMenu = (
<Image
src={'https://github.com/mshaaban0.png'}
alt="UserName profile image"
roundedCircle
style={{ width: '40px' }}
/>
)
<NavDropdown id="nav-dropdown-dark-example" title={UserMenu}>
//....
</NavDropdown>

How to call an event on tabs changed in react-bootstrap

I've implemented Navigation Tabs in my React application using React-Bootstrap.
Like this:
<Tabs defaultActiveKey={1}>
<Tab eventKey={1} title="Log in">
{/* Irrelevant code */}
</Tab>
<Tab eventKey={2} title="Sign up">
{/* Irrelevant code */}
</Tab>
</Tabs>
Now on changing tabs I would like to call the following funtion:
changeTab(login) {
if (login)
this.setState({ heading: "Log in" })
else
this.setState({ heading: "Sign up" })
}
Where login is a Boolean that will be true for when the Log in tab is selected and false when the Sign up tab is selected.
How can I do that?
Edit:
I've figured out that you can call a function on when the tabs are clicked like this:
<Tabs defaultActiveKey={1} onClick={()=>this.changeTab()}>
<Tab eventKey={1} title="Log in">
{/* Irrelevant code */}
</Tab>
<Tab eventKey={1} title="Sign up">
{/* Irrelevant code */}
</Tab>
</Tabs>
But how can I know which tab was clicked? I need it to change the state based on which tab is clicked.
You need to use onSelect in the Tabs component.
Like this:
<Tabs defaultActiveKey={1} onSelect={this.handleSelect()}>
<Tab eventKey={1} title="Log in">
{/* Irrelevant code */}
</Tab>
<Tab eventKey={2} title="Sign up">
{/* Irrelevant code */}
</Tab>
</Tabs>
And then make this your handleSelect function:
handleSelect(key) {
if (key === 1)
this.setState({ heading: "Log in" })
else
this.setState({ heading: "Sign up" })
}
<Tab.Container id="" defaultActiveKey={key} onSelect={this.handleSelect}>
<Nav variant="tabs">
<Nav.Item>
<Nav.Link eventKey={'1'}>Staking</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey={'2'}>Providers</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey={'3'}>Overview</Nav.Link>
</Nav.Item>
</Nav>
<Tab.Content>
<Tab.Pane eventKey={'1'}>
<Row>
<Col>
1111
</Col>
</Row>
</Tab.Pane>
</Tab.Content>
<Tab.Content>
<Tab.Pane eventKey={'2'}>
<div>22222</div>
</Tab.Pane>
</Tab.Content>
<Tab.Content>
<Tab.Pane eventKey={'3'}>
<div>333</div>
</Tab.Pane>
</Tab.Content>
</Tab.Container>
Now in your state add 'key' field with initial value '1'
constructor(props) {
super(props);
this.state = {
key: '1'
};
}
Then write a function
handleSelect = (key) => {
console.log(key,';;',typeof key)
if(key === '1') {
console.log('ll', key)
} else if(key === '2') {
console.log('ll', key)
} else if(key === '3') {
console.log('ll', key)
}
}
Initially when the page loades, the function is not called so you can make API calls or any thing you want to do in the 1st tab, in componentDidMount or any other function and place it in the 1st tab i.e where I've written 1111,after this when you click another tab, handleSelect function is called and based on key value with use if..else statement to perform specific task for specific tab.
Hope this helps. If any issue please let us know in the comment section.
Here, You can use onSelect as Barry Michael Doyle said. Let me post you a sample code to make it more clear for you.
function Example() {
return (
<Tabs defaultActiveKey="home" id="uncontrolled-tab-example"
className="mb-3" onSelect={(e) => handleClick(e)}>
<Tab eventKey="homeTab" title="Home">
</Tab>
<Tab eventKey="profileTab" title="Profile">
</Tab>
<Tab eventKey="contactTab" title="Contact">
</Tab>
</Tabs>
);
function handleClick(e) {
console.count(e);
//result will be the eventKey of the tab you clicked on.
// `homeTab` (when clicked on home tab)
// `profileTab` (when clicked on profile tab)
// `constactTab` (when clicked on Contact tab)
}
}

Reactjs Material UI Tabs label will disappear and will retain logo for smaller screen

So I am new in using Material UI Tabs and I want the labels to disappear when the screen is resized. for example when the screen is in 500px or smaller, the logo will only retain and the label will disappear.
below is the sample code of my material ui Tabs
<Tabs onChange={this.handleChange.bind(this)} value={this.state.status}>
<Tab icon={<FontIcon className="fa fa-cogs" />} label="Process" value='orderProcessing' />
<Tab icon={<FontIcon className="fa fa-money" />} label="Paid" value='orderConfirmed' />
<Tab icon={<FontIcon className="fa fa-industry" />} label="Production" value='onProduction' />
<Tab icon={<FontIcon className="fa fa-shopping-cart" />} label="Qc and Packaging" value={3} />
<Tab icon={<FontIcon className="fa fa-cart-arrow-down" />} label="Sold" value='sold' />
<Tab icon={<FontIcon className="fa fa-ban" />} label="Cancelled" value='cancelled' />
<Tab icon={<FontIcon className="fa fa-globe" />} label="All Transactions" value='' />
</Tabs>
You can accomplish this by using this.isDeviceSize(). Here is an example:
Updated to show one tab with only a label and the other with only the icon when the screen is small. Previously both tabs removed the icons and the question was actually asking how to remove the labels. Now the example below shows how to do either.
import React from 'react'
import {Mixins, Tabs, Tab} from 'material-ui'
const {StylePropable, StyleResizable} = Mixins
import {MapsDirectionsRun} from 'material-ui/lib/svg-icons'
export default React.createClass({
propTypes: {
onChangeMuiTheme: React.PropTypes.func,
},
contextTypes: {
muiTheme: React.PropTypes.object,
},
mixins: [StylePropable, StyleResizable],
render() {
return (
<Tabs>
<Tab
label="Tab 1"
icon={this.isDeviceSize(StyleResizable.statics.Sizes.MEDIUM) ? (<MapsDirectionsRun />) : null}>
Tab 1 content
</Tab>
<Tab
label={this.isDeviceSize(StyleResizable.statics.Sizes.MEDIUM) ? "Tab 2" : null}
icon={<MapsDirectionsRun />}>
Tab 2 content
</Tab>
</Tabs>
)
}
})

Resources