How do I share state between routes in React-Router? - reactjs

I've seen a few questions similar to this on SO but none that quite matched my needs. I'm using React and Material-UI to make a dashboard. I'm using Material-UI's mini variant drawer as a sidebar, with links that should display routes when clicked. The sidebar can be opened by clicking a button, which updates a state variable and adjusts the CSS className of the sidebar. This causes the sidebar/drawer to "slide" open.
If I click a link on the sidebar, I can easily display a desired route. However, I can't get the route to also "slide" to the side when the sidebar/drawer opens. It will probably be easier to understand by looking at the code, so I've included a link to a codesandbox below:
https://codesandbox.io/s/appbar-with-react-router-bkogj?file=/src/App.js
I basically copy and pasted everything from the Material-UI website (using v4 I believe), then added the route myself. Would appreciate any feedback on how to solve this issue.

For this I think the MiniDrawer component needs to render the content since it necessarily is aware of the space the appbar and drawer components occupy.
MiniDrawer
Take and render a children prop.
export default function MiniDrawer({ children }) {
...
return (
<div className={classes.root}>
<CssBaseline />
<AppBar
...
>
...
</AppBar>
<Drawer
...
>
...
</Drawer>
<main className={classes.content}>{children}</main>
</div>
);
}
App
Render the Outlet as a child component.
export default function App() {
return (
<div className="App">
<AppBar>
<Outlet />
</AppBar>
</div>
);
}
RejectTable
Remove the excess margin so it fills the content area the parent component allows.
const useStyles = makeStyles((theme) => ({
content: {
flexGrow: 1,
padding: theme.spacing(3),
height: "100%",
// marginLeft: "4em" // <-- remove
}
}));

Related

React MUI <Tab> component "Expected an element type that can hold a ref."

I am working with React MUI Tabs and am running across:
Warning: Failed prop type: Invalid prop component supplied to ForwardRef(ButtonBase). Expected an element type that can hold a ref. Did you accidentally provide a plain function component instead?`
I have read many threads, Including This One -- And surrounding my element in a <div> or a <Box> does not do the trick.
I have also read This Documentation Which suggests that it's "just a warning" to me even though I am not trying to pass a ref.
Can anyone find what is wrong with the following (if anything):
<Tab label="Project Info" {...a11yProps(0)} component={() => (
<Box onClick={() => setValue(0)}>
<Icon sx={{color: ywpBlue}} title="Grid View">info</Icon>
<Typography sx={{fontSize:"20px"}} mt={-3}>
Project Info
</Typography>
</Box>
)}/>
I have also tried:
<Tab label="Project Info" {...a11yProps(0)} component={props =>
<Box {...props} onClick={() =>
To no avail.
The <Tabs> display fine, and function as expected .. I just HATE seeing red "Warnings" in my DevTools Console.
The Tab component doesn't have a prop component. Under the hood, Tab is using ButtonBase, hence when it is being provided component it complains. If you want to just add an Icon and style, you should follow the docs on customizing tabs here. You can provide an Icon, and center the label and styled like so:
import * as React from "react";
import Tabs from "#mui/material/Tabs";
import Tab, { TabProps } from "#mui/material/Tab";
import PhoneIcon from "#mui/icons-material/Phone";
import { styled } from "#mui/material";
const CustomTab = styled(Tab)<TabProps>(({ theme }) => ({
"&.MuiButtonBase-root": {
fontSize: "20px",
marginTop: -3
}
}));
export default function IconTabs() {
return (
<Tabs>
<CustomTab icon={<PhoneIcon />} label="phone" />
</Tabs>
);
}
If you need more control, you could consider using TabUnstyled in the base library and you will have complete control of the components show in the base docs

Link to a `ref` in another component in React

I have a footer component in my React app which contains links to different sections of the website.
Instead of lots of different components to render for each section, I am just making a main component for each section and then within this component there are different parts of the page. i.e
First page
section 1
section 2
section 3
If I want to be able to click a link on the footer to take me to section 3 of the first page, is this possible? Currently I wrote the code in the footer to take me to a new route,
<Grid item xs={12} sm={3}>
<Typography variant='h6'>Golf</Typography>
<List>
<ListItem component={NavLink} color='text.secondary' to='/section-1' sx={{textDecoration:'none', color: 'black'}}>Section 2</ListItem>
<ListItem component={NavLink} color='text.secondary' to='/section-2' sx={{textDecoration:'none', color: 'black'}}>Section 2</ListItem>
</List>
</Grid>
But now I want it to take me to a route '/firstpage' and then to section 1 on that page.
On each page I have all the sections wrapped in a div with a ref and using the useRef hook
const section1 = useRef(null);
const section2 = useRef(null);
const scrollToSection = (elementRef: any) => {
window.scrollTo({
top: elementRef.current.offsetTop - 110,
behavior: 'smooth'
})
}
return (
<>
<div ref={section1}>
//code
</div>
<div ref={section2}>
//code
</div>
</>
)
On each page I have a basic nav system at the top so when I click on a link it scrolls to the relevant section using the scrollToSection function onClick={() => scrollToSection(section2)}
Can I use what I already have to be able to let a user click on a link in the footer and it will take them to the correct route and then automatically scroll to that section.

React Change Navbar color on specific page using React Helmet?

So I have a transparent navbar background on my home page, but I need it to change background color when I navigate to my services page to #000.
I figured out how to change the page background with helmet, but I don't understand how I would target the navbar and change the color since I am using a layout component that renders on every page.
const Layout = ({ children }) => {
return (
<>
<Helmet bodyAttributes={{ class: "image-page" }} />
<Navbar />
<main>{children}</main>
<Footer />
</>
)
}
You need to get the location from the default's Gatsby's props to make your checks.
Inside your <Navbar> component, you will need to get the location via props and add a class name to it if it matches your services page. It should look like:
const Navbar= ({ location }) => {
return <div className={`${location.pathname === /services/} ? 'whiteClassName': 'regularClassName'`}>Your navbar content</div>
}
In the same way that you destructurate children in the <Layout> component, you can do exactly the same with location. Since it's a default prop, it will be available everywhere. Once you have your current location, you only need to add a custom class if it fits a condition to your element and make your CSS magic.

Load content from sidebar in react

I found this template of react sidebar which I have implemented successfully. However, I am stuck on how to load the content.
<SubMenu
title="Users"
icon={faBriefcase}
items={["Create", "List"]}
/>
How do I route the content I want to show when a menu item is selected? (either Create or List in the example above)
As React provides with Link Tags to Route.
Do it like this. Your items should be wrapped in a Link tag to route.
<SubMenu
title="Users"
icon={faBriefcase}
items={[
<Link to"path">"Create"</Link>,
<Link to"path">"List"</Link>
]}
/>
As per your comment you need something like this
<Layout>
<App/>
</Layout>
Whereas Layout is
const Layout = ({children}) => {
return(
<>
<Appbar />
<Sidebar />
<main>
{children} // your whole app renders here
</main>
</>
)
}
export default Layout;
You could add a .sidenavactive class to main tag that becomes active when side bar is opened so you adjust or push page content using .sidenavactive.
Now when you will change route in Sidebar items. Just the main content will change.

How can I center something in Material UI?

So I have an AppBar component for my Header, and I would like to center the title in the AppBar. As you can see I would have a button on the left and a button on the right. I would have these buttons hugging the left and the right, respectively.
const styles = {
root: {
flexGrow: 1
}
};
class Header extends Component {
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<LeftButton />
<Typography variant="h4" color="inherit">
Title
</Typography>
<RightButton />
</Toolbar>
</AppBar>
</div>
);
}
}
What would be an approach to center the title?
My initial thought was having a grid of three columns, and then left-aligning the first, center-aligning the second, and right-aligning the third.
Another possibility is to give the title FlexGrow property and then setting text-align to center, but the issue with that approach would be that if the content on the left and right side are unequal, it would be slightly off center.
you can use withStyles() that is exported by MaterialUI to put some CSS into components.
And, they have a example that make a AppBar, i guess will help! that i edit and make this.
In the original code, in the class 'grow', i remove the flexGrow: 1 and put margin: "auto"

Resources