Link to a `ref` in another component in React - reactjs

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.

Related

How to properly display the object value to another separate page component after a button is clicked in React? (From object form to proper form)

I have created a functionality for my "menu item buttons" to display their assigned data through an object format into a separate page component called "SidePage" (gained help also here in StackOverflow). What I am not sure is that if this functionality that I have created is a formal or effective one since I am planning to implement a backend functionality into my full main app. The functionality involves useState, onClick, and onSelected.
I used props to hold the resulting data after the "menu item button" is clicked.
(Chicken Button should be clicked first in order to display the menu item buttons)
SidePage source code:
import * as React from "react";
import { Typography } from "#mui/material";
export default function SidePage(props) {
return (
<div>
<Typography sx={{ mt: 20 }}>Menu Item Details:</Typography>
<div>{props.menuItemDetails}</div>
</div>
);
}
HomeOrderPage (main page) source code:
import * as React from "react";
import { useState } from "react";
import { Stack } from "#mui/material";
import ButtonCategoryStyle from "./ButtonCategoryStyle";
import ChickenButtons from "./categoryButtons/ChickenButtons";
import SidePage from "./SidePage";
const categories = ["Chicken"];
export default function HomeOrderPage() {
const [myCategory, setMyCategory] = useState("");
const [food, setFood] = useState(null);
return (
<div>
<Stack spacing={0} direction="row">
{categories.map((category) => (
<ButtonCategoryStyle
title={category.toLocaleUpperCase()}
key={category}
onClick={() => setMyCategory(category)}
/>
))}
</Stack>
<div>
<p>
{myCategory === "Chicken" && <ChickenButtons onSelected={setFood} />}
</p>
{/* ------------------------------------------------------------------------------------------------ */}
</div>
{/* Displays object after menu item is clicked and renders the side page to show the menu item details:: */}
<div
style={{
backgroundColor: "blue"
}}
>
<SidePage
menuItemDetails={
food && <pre sx={{ ml: 120 }}>{JSON.stringify(food, null, 2)}</pre>
}
/>
</div>
</div>
);
}
Full source code (CodeSandbox): https://codesandbox.io/s/nice-stack-question-page-component-data-transfer-ejebxz?file=/src/HomeOrderPage.jsx
What I also want is to store the property values of the object into variables (in order to display the details of the selected menu item button properly but I am not sure how to do this since I am baffled with using this.state or still using props for this.
Hoping for all of your response as this would help me a lot with my first big React project that I am working on. Thank you very much everyone!
Since you already have props. Why copy it to state? Just keep single source of truth.

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

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
}
}));

React Accordion Closing on state change

I have 2 tabs which have accordions in those tabs. Whenever user switch between the tabs with accordion open in one tab, again coming back to the previous tab then the accordion is closed. How can we make the accordion to open until user close it.
I am using React Accordion installed from npm.
Here i am in Tab 1 with accordion as opened, as shown in image
Now i switched to tab 3, as shown in image
Now again i switched from tab 3 to tab 2 then you can see here the accordion is closed automatically. Here I don't want to close the accordion on changing of tabs, it should close until user closes it.
This is the problem i am facing here.
You can do this. Have a specific tabs state array for all tabs and store the current state(true=open & false=close) of each tab.
And updating only the state of current tab and keeping the state of rest of the tabs as same.
import { useState } from "react";
import "./styles.css";
export default function App() {
const tabNumbers = 4; //number of tabs
const [tabs, setTabs] = useState([...Array(tabNumbers).fill(false)]); //a state storing state of tabs
const [currentTab, changeTab] = useState(0); //currently active tab
function toggleIndex() {
const updatedTabs = [...tabs];
updatedTabs[currentTab] = !updatedTabs[currentTab]; //only toggle current tab's state
setTabs(updatedTabs); //store updated tab's state
}
return (
<div className="App">
<div style={{ display: "flex", gap: "2rem" }}>
{[...Array(tabNumbers)].map((_, index) => (
<div
style={{ cursor: "pointer" }}
key={index}
onClick={() => changeTab(index)}
>
Tab {index}
</div>
))}
</div>
<div>
<button onClick={toggleIndex}>
This is the tab {currentTab}.<br /> This is currently{" "}
{tabs[currentTab] ? "open" : "close"}
</button>
</div>
</div>
);
}

How do you get Material-UI Drawer to highlight the page it is currently at?

I'm currently trying to implement a website using Material-UI's drawer component. It works, when I click on the Drawer Items, it routes me to the correct pages.
But how do I get the individual Drawer Items to highlight the current page it is on.
For instance, if I am on /dashboard page, and if the Drawer Item for Dashboard page should be highlighted (different color and styles) to indicate that I am currently on that page dynamically.
Haven't manage to find any good solutions online and the Material-UI docs doesn't have a demo of how this is possible, great to hear how you all do it.
You can highlight the current ListItem in the Drawer by setting selected props to true and use the pathname information to determine if the item matches the current route:
const routes = {
Home: "/",
About: "/about",
Users: "/users"
};
const { pathname } = useLocation();
<List>
{Object.keys(routes).map((routeName, index) => {
const route = routes[routeName];
return (
<ListItem selected={route === pathname} button key={route}>
<ListItemText primary={routeName} />
</ListItem>
);
})}
</List>
Live Demo

How Can I make my React Button Component updates CSS only on the specific page?

So I created this button component using the following code
const STYLES = ['btn--primary', 'btn--outline', 'btn--test'];
const SIZES = ['btn--medium', 'btn--large'];
const DISPLAY = ['btn--show', 'btn--hidden'];
export const Button = ({
children,
type,
onClick,
buttonStyle,
buttonSize,
buttonDisplay
}) => {
const checkButtonStyle = STYLES.includes(buttonStyle)
? buttonStyle
: STYLES[0];
const checkButtonSize = SIZES.includes(buttonSize) ? buttonSize : SIZES[0];
const checkButtonDisplay = DISPLAY.includes(buttonDisplay)
? buttonDisplay
: DISPLAY[0];
return (
<Link to='/sign-up'>
<button
className={`btn ${checkButtonStyle} ${checkButtonSize} ${checkButtonDisplay}`}
onClick={onClick}
type={type}
>
{children}
</button>
</Link>
);
So I have this button component inside of my navbar component and I also have it inside of my home page section component.
My issue is that whenever I shrink the page to mobile, I want to make the button component in the navbar to display: none and then on the home section I want it to show
What ends up happening is that since it's a component, any CSS style I add to it will go on any other page that is using the component, so basically my button disappears on the home page section when I need it to display
I tried to add an Id to the button component, but that didn't work
<Button id='nav-btn' buttonStyle='btn--outline'>
SIGN UP
</Button>
and I don't know how I'd add a custom class or id to the navbar button without it applying to all the other button components on my homepage
Hide it with an expression, e.g., { showButton && <Button /> }. If showButton is true, you'll see the button, if not, you won't.
If you want to do it via CSS, use a media-query to set display: none on whatever screen size it's supposed to disappear on.
Edit in response to the comment
#media (max-height: 960px) {
display: none;
}
That reads, "If the height is less than 960px, set this property."
If you want a "special" button that hides on a screen size, create a higher-order component that wraps your button.
const NinjaButton => () => {
// do stuff
return <Button cssOverrideProp={cssWithMediaQueryThatHides} />
}
In Button, you can conditionally apply that css,
className=`{/* your other css */ ${cssOverrideProp || ''}}`
Then you can use that button anywhere it's supposed to hide.

Resources