Why react route is not working in material ui? - javascript

I am creating tab and adding routing inside the first tab. But the desired page is not shown after a click on the link. Although after refreshing the page the corresponding page will display on screen. Anyone please help me to solve this where I'm doing wrong im using material UI for this
function TabPanel(props) {
const { children, value, index, ...other } = props;
return (
<Typography
component="div"
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
<Box p={3}>{children}</Box>
</Typography>
);
}
TabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.any.isRequired,
value: PropTypes.any.isRequired,
};
function a11yProps(index) {
return {
id: `simple-tab-${index}`,
'aria-controls': `simple-tabpanel-${index}`,
};
}
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1,
backgroundColor: theme.palette.background.paper,
},
}));
export default function SimpleTabs() {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<div className={classes.root}>
<AppBar position="static">
<Tabs value={value} onChange={handleChange} aria-label="simple tabs example">
<Tab label="Item One" {...a11yProps(0)} />
<Tab label="Item Two" {...a11yProps(1)} />
<Tab label="Item Three" {...a11yProps(2)} />
</Tabs>
</AppBar>
<TabPanel value={value} index={0}>
<Router>
<ul className="navbar-nav mr-auto" >
<li><Link to={'/Text'} className="nav-link"><i class="fas fa-text-height"></i> Text </Link></li>
</ul>
<div>
</div>
</Router>
</TabPanel>
<TabPanel value={value} index={1}>
Item Two
</TabPanel>
<TabPanel value={value} index={2}>
Item Three
</TabPanel>
<Router>
<Switch>
<Route exact path='/Text' component={Text} />
</Switch>
</Router>
</div>
);
}
so please tell me where should i change or what is wrong with the code.

Why are you declaring your Router component twice? There should be only one Router component wrapping whole application (not talking about special cases when 2+ are needed) which is the reason your Link and your Route are not in sync. Try something like this:
return (
<Router>
<div className={classes.root}>
<AppBar position="static">
<Tabs value={value} onChange={handleChange} aria-label="simple tabs example">
<Tab label="Item One" {...a11yProps(0)} />
<Tab label="Item Two" {...a11yProps(1)} />
<Tab label="Item Three" {...a11yProps(2)} />
</Tabs>
</AppBar>
<TabPanel value={value} index={0}>
<ul className="navbar-nav mr-auto" >
<li><Link to={'/Text'} className="nav-link"><i class="fas fa-text-height"></i> Text </Link></li>
</ul>
<div>
</div>
</TabPanel>
<TabPanel value={value} index={1}>
Item Two
</TabPanel>
<TabPanel value={value} index={2}>
Item Three
</TabPanel>
<Switch>
<Route exact path='/Text' component={Text} />
</Switch>
</div>
</Router>
);

Related

getting typescript error in react + mui while creating tabs?

I am creating custom hook of accordion component . I am getting below error
export default const Tabs: OverridableComponent<TabsTypeMap<{}, ExtendButtonBase<ButtonBaseTypeMap<{}, "button">>>>
here is my code
https://codesandbox.io/s/epic-easley-ek3ev5?file=/src/App.tsx
export default function BasicTabs() {
const { register, value } = useTabs();
return (
<Box sx={{ width: "100%" }}>
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
<Tabs {...register()} aria-label="basic tabs example">
<Tab label="Item One" {...a11yProps(0)} />
<Tab label="Item Two" {...a11yProps(1)} />
<Tab label="Item Three" {...a11yProps(2)} />
</Tabs>
</Box>
<TabPanel value={value} index={0}>
Item One
</TabPanel>
<TabPanel value={value} index={1}>
Item Two
</TabPanel>
<TabPanel value={value} index={2}>
Item Three
</TabPanel>
</Box>
);
any suggestion
In your useTabs you should change change React.ChangeEvent to React.SyntheticEvent as the signature of onChange is function(event: React.SyntheticEvent, value: any) => void in <Tabs /> : https://mui.com/material-ui/api/tabs/

Display selected tab item into url path

I want to display selected tab item into url path. I found this Material UI example:
import * as React from 'react';
import Tabs from '#mui/material/Tabs';
import Tab from '#mui/material/Tab';
import Typography from '#mui/material/Typography';
import Box from '#mui/material/Box';
interface TabPanelProps {
children?: React.ReactNode;
index: number;
value: number;
}
function TabPanel(props: TabPanelProps) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`vertical-tabpanel-${index}`}
aria-labelledby={`vertical-tab-${index}`}
{...other}
>
{value === index && (
<Box sx={{ p: 3 }}>
<Typography>{children}</Typography>
</Box>
)}
</div>
);
}
function a11yProps(index: number) {
return {
id: `vertical-tab-${index}`,
'aria-controls': `vertical-tabpanel-${index}`,
};
}
export default function VerticalTabs() {
const [value, setValue] = React.useState(0);
const handleChange = (event: React.SyntheticEvent, newValue: number) => {
setValue(newValue);
};
return (
<Box
sx={{ flexGrow: 1, bgcolor: 'background.paper', display: 'flex', height: 224 }}
>
<Tabs
orientation="vertical"
variant="scrollable"
value={value}
onChange={handleChange}
aria-label="Vertical tabs example"
sx={{ borderRight: 1, borderColor: 'divider' }}
>
<Tab label="Item One" {...a11yProps(0)} />
<Tab label="Item Two" {...a11yProps(1)} />
<Tab label="Item Three" {...a11yProps(2)} />
<Tab label="Item Four" {...a11yProps(3)} />
<Tab label="Item Five" {...a11yProps(4)} />
<Tab label="Item Six" {...a11yProps(5)} />
<Tab label="Item Seven" {...a11yProps(6)} />
</Tabs>
<TabPanel value={value} index={0}>
Item One
</TabPanel>
<TabPanel value={value} index={1}>
Item Two
</TabPanel>
<TabPanel value={value} index={2}>
Item Three
</TabPanel>
<TabPanel value={value} index={3}>
Item Four
</TabPanel>
<TabPanel value={value} index={4}>
Item Five
</TabPanel>
<TabPanel value={value} index={5}>
Item Six
</TabPanel>
<TabPanel value={value} index={6}>
Item Seven
</TabPanel>
</Box>
);
}
https://mui.com/components/tabs/#VerticalTabs.tsx
Sandbox: https://codesandbox.io/s/verticaltabs-material-demo-forked-yyqhm
I found this code example how to add url param:
https://v5.reactrouter.com/web/example/nesting
Do know how I can implement the code to display selected tab into url link. Example: https://yyqhm.csb.app/<selected_tab>
Main Solution
Check this solution out.
It utilizes react-router-dom, so wrap your root component with BrowserRouter
ReactDOM.render(
<StyledEngineProvider injectFirst>
<BrowserRouter>
<Demo />
</BrowserRouter>
</StyledEngineProvider>,
document.querySelector("#root")
);
This is the updated code - the basic idea is to use pathname as the value to check for, and update it when a tab gets picked:
import { Routes, Route, useNavigate } from "react-router-dom";
export default function VerticalTabs() {
const [value, setValue] = React.useState(0);
const navigate = useNavigate();
const handleChange = (event: React.SyntheticEvent, newValue: number) => {
navigate(newValue);
setValue(newValue);
};
return (
<Box
sx={{
flexGrow: 1,
bgcolor: "background.paper",
display: "flex",
height: 224
}}
>
<Tabs
orientation="vertical"
variant="scrollable"
onChange={handleChange}
value={
window.location.pathname == "/"
? "/item_one"
: window.location.pathname
}
aria-label="Vertical tabs example"
sx={{ borderRight: 1, borderColor: "divider" }}
>
<Tab value="/item_one" label="Item One" {...a11yProps(0)} />
<Tab value="/item_two" label="Item Two" {...a11yProps(1)} />
<Tab value="/item_three" label="Item Three" {...a11yProps(2)} />
</Tabs>
<Routes>
<Route
path="/"
element={
<TabPanel value={value} index={0}>
Item One
</TabPanel>
}
/>
<Route
path="/item_one"
element={
<TabPanel value={value} index={0}>
Item One
</TabPanel>
}
/>
<Route
path="/item_two"
element={
<TabPanel value={value} index={1}>
Item Two
</TabPanel>
}
/>
<Route
path="/item_three"
element={
<TabPanel value={value} index={2}>
Item Three
</TabPanel>
}
/>
</Routes>
</Box>
);
}
Alternative
Here is a link to the working version of the code.
The code below reads the pathname of the current page, then sets it to state.
...
React.useEffect(() => {
setValue( +window.location.pathname.substring(1) );
}, []);
You could also define a dictionary that functions as a sort of inverted index to match custom pathnames to their related index value, or maybe a typescript enum.
{
'item-one': 1,
'item-two': 2,
'item-three': 3,
1: 'item-one',
2: 'item-two',
3: 'item-three'
}
Whenever a tab is selected, you can set the index to the path by manipulating history.
const handleChange = (event: React.SyntheticEvent, newValue: number) => {
window.history.replaceState({}, "", "/" + newValue);
setValue(newValue);
};
...

How do we call this type of navigation tab menu

How do we call this tab menu with the next and preview option and also is there any material-ui component of it
As per the comment, I have prepared an example for scrollable tab using material ui. Please have a look.
import React from 'react';
import PropTypes from 'prop-types';
import {makeStyles} from '#material-ui/core/styles';
import AppBar from '#material-ui/core/AppBar';
import Tabs from '#material-ui/core/Tabs';
import Tab from '#material-ui/core/Tab';
import Typography from '#material-ui/core/Typography';
import Box from '#material-ui/core/Box';
function TabPanel(props) {
const {children, value, index, ...other} = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`scrollable-auto-tabpanel-${index}`}
aria-labelledby={`scrollable-auto-tab-${index}`}
{...other}
>
{value === index && (
<Box p={3}>
<Typography>{children}</Typography>
</Box>
)}
</div>
);
}
TabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.any.isRequired,
value: PropTypes.any.isRequired,
};
function a11yProps(index) {
return {
id: `scrollable-auto-tab-${index}`,
'aria-controls': `scrollable-auto-tabpanel-${index}`,
};
}
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
width: '100%',
backgroundColor: theme.palette.background.paper,
},
}));
export default function ScrollableTabsButtonAuto() {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<div className={classes.root}>
<AppBar position="static" color="default">
<Tabs
value={value}
onChange={handleChange}
indicatorColor="primary"
textColor="primary"
variant="scrollable"
scrollButtons="auto"
aria-label="scrollable auto tabs example"
>
<Tab label="Item One" {...a11yProps(0)} />
<Tab label="Item Two" {...a11yProps(1)} />
<Tab label="Item Three" {...a11yProps(2)} />
<Tab label="Item Four" {...a11yProps(3)} />
<Tab label="Item Five" {...a11yProps(4)} />
<Tab label="Item Six" {...a11yProps(5)} />
<Tab label="Item Seven" {...a11yProps(6)} />
<Tab label="Item Eight" {...a11yProps(7)} />
<Tab label="Item Nine" {...a11yProps(8)} />
<Tab label="Item Ten" {...a11yProps(9)} />
</Tabs>
</AppBar>
<TabPanel value={value} index={0}>
Item One
</TabPanel>
<TabPanel value={value} index={1}>
Item Two
</TabPanel>
<TabPanel value={value} index={2}>
Item Three
</TabPanel>
<TabPanel value={value} index={3}>
Item Four
</TabPanel>
<TabPanel value={value} index={4}>
Item Five
</TabPanel>
<TabPanel value={value} index={5}>
Item Six
</TabPanel>
<TabPanel value={value} index={6}>
Item Seven
</TabPanel>
<TabPanel value={value} index={7}>
Item Eight
</TabPanel>
<TabPanel value={value} index={8}>
Item Nine
</TabPanel>
<TabPanel value={value} index={9}>
Item Ten
</TabPanel>
</div>
);
}
This type of UI elements is called "chips".
https://material-ui.com/components/chips/
Note, that usually it is not used for navigation, but rather for displaying tags, categories, etc.

Material-UI : tab not responsive with a datatable inside

I use the Simple Tabs from Material-UI and I have one Tab how contain a Datatable (React-Data_Table) and this tab is not responsive like other when the table is full
Empty
Full
The code
<Grid item xs={12}>
<Paper className={classes.paper}>
<AppBar position="static" className={classes.appBar}>
<Tabs value={value} onChange={handleChange} classes={{ indicator: classes.indicator }} variant="fullWidth">
<Tab label="Tableau" {...a11yProps(0)} />
<Tab label="Graphique" {...a11yProps(1)} />
<Tab label="Carte" {...a11yProps(2)} />
</Tabs>
</AppBar>
<TabPanel value={value} index={0}>
<Table sections={props.sections}/>
</TabPanel>
<TabPanel value={value} index={1}>
<Graph />
</TabPanel>
<TabPanel value={value} index={2}>
<AppMap />
</TabPanel>
</Paper>
</Grid>
I don't know how to fix this except maybe make a CSS to change width with size screen
Thanks for the help
If the child element is exceeding it's parent's size(container element) I would recommend to try using max-width to ensure the width doesn't pass a certain limit.

Avoid re-rendering in React when switching between tabs

I have a react application using material-ui to create tabs.
<div className={classes.root}>
<AppBar position="static">
<Tabs value={value} onChange={handleChange}>
<Tab label="Item One" />
<Tab label="Item Two" />
<Tab label="Item Three" />
</Tabs>
</AppBar>
{value === 0 && <TabContainer id={1}>Item One</TabContainer>}
{value === 1 && <TabContainer id={2}>Item Two</TabContainer>}
{value === 2 && <TabContainer id={3}>Item Three</TabContainer>}
</div>
The TabContainer is a functional component and does some heavy computation.
Is it possible to prevent TabContainer from re-rendering when switching between tabs?
Update:
Check my answer for a solution with React functional components and css classes.
In order to prevent TabContainer from re-rendering. You have to
Render all TabContainer data at once instead of rendering based on value.
You have to play with CSS and have to display only that tab which is currently active.
Also you can make your component as PureComponent or you can override shouldComponentUpdate() lifecycle method to stop extra re-rendering of your react component.
Update/Partial Solution:
With the below code (based on Rahul Jain's answer) using css classes to display the active TabContainer, the memoized functions seems to be really memoized.
const useTabContainerStyles = makeStyles((theme: Theme) => createStyles({
root: {
padding: 8 * 3
},
tabcontainerInActive: {
display: "none"
}
})
);
function TabContainer(props: TabContainerProps) {
const styles = useTabContainerStyles({});
console.log("In TabContainer");
const doubleValue = useMemo(() => double(props.id), [props.id]);
return (
<Typography
id={props.id.toString()}
component="div"
className={classnames(styles.root, {
[styles.tabcontainerInActive]: !props.active
})}
>
{props.children + " " + doubleValue}
</Typography>
);
}
export default function SimpleTabs() {
const classes = useStyles({});
const [selectedTab, setSelectedTab] = React.useState(0);
function handleChange(event: React.ChangeEvent<{}>, newValue: number) {
setSelectedTab(newValue);
}
return (
<div className={classes.root}>
<AppBar position="static">
<Tabs value={selectedTab} onChange={handleChange}>
<Tab label="Item One" />
<Tab label="Item Two" />
<Tab label="Item Three" />
</Tabs>
</AppBar>
{/* */}
<TabContainer id={0} active={selectedTab === 0}>
Item One
</TabContainer>
<TabContainer id={1} active={selectedTab === 1}>
Item Two
</TabContainer>
<TabContainer id={2} active={selectedTab === 2}>
Item Three
</TabContainer>
</div>
);
}

Categories