When navigating from one page to another, I would like the user to be automatically scrolled to the top, i.e. scrollTo(0, 0).
According to the react-router docs on scroll restoration the recommended approach is to setup a component ScrollToTop and wrap your routes within this.
While this works well and the user is scrolled to the top for any route nested within the ScrollToTop component, if the component is placed within a Switch component, the Switch does not function like a Switch any longer; meaning that it will render all routes that it matches instead of the first one.
Alternatively, placing the ScrollToTop outside of the Switch, it no longer scrolls the user to the top.
Version: react-router-v4
I'm not sure specifically about the scrolling, but you can attach a listener to browserHistory which may be an easy way to do this (I don't think onUpdate works with v4):
const browserHistory = createBrowserHistory();
browserHistory.listen((location, action) => {
window.scrollTo(0, 0);
});
<Router history={browserHistory} />
I had the same issue what i did was Whenever the is updated it will take the user to the scrollTo(0,0)
<Router onUpdate={() => window.scrollTo(0, 0)} history={createBrowserHistory()}>
...
</Router
If above does not work :
In react-router-v4 scroll Restoration
This is straightforward to handle with a component that will scroll the window up on every navigation, make sure to wrap it in withRouter to give it access to the router’s props:
componentDidUpdate(prevProps) {
if (this.props.location !== prevProps.location) {
window.scrollTo(0, 0)
}
}
render() {
return this.props.children
}
}
Then render it at the top of your app, but below Router
const App = () => (
<Router>
<ScrollToTop>
<App/>
</ScrollToTop>
</Router>
)
Above code is copied from React-Router web guides
I managed to solve this using the react-router-v4 scroll Restoration and placing the ScrollToTop outside of the Switch. Also remember to use withRouter otherwise it won't work.
Related
I'm relatively somewhat new to the whole world of react, DOM, etc.
This probably sounds like a simple issue or a dumb question, bear with me.
My code for the routing stuff looks like:
function App() {
return (
<div className="content">
<SideBar>
<Router>
<Routes>
<Route path="/dashboard" element={Dashboard} />
</Routes>
</Router>
</SideBar>
</div>
);
}
export default App;
My SideBar is a component of a sidebar, it should allow users to click on a button and to navigate to a new page. In this case, a dashboard. However, all pages basically load at the start of me going to my localhost/
I've tested this out due to a console.log loading from the dashboard basically popping up in other places, not just localhost/dashboard.
I'm using MaterialUI, React.
My SideBar.js looks like this:
<List>
{BarData.map((item, key) => {
return (
<ListItemButton
key={key}
onClick={() => {
window.location.pathname = item.link;
}}
Has things removed, but here is my SideBar data (in another folder).
export const BarData = [
{
text: "Dashboard",
icon: <HomeRounded color="#637381" />,
link: "/dashboad",
},
Am I doing something wrong here? I'm completely new to React, DOM, etc. So I'm unsure if this is the best way to go in general.
In short, what I'm trying to achieve is:
Have multiple pages, if a user clicks a button, it'll navigate them to that specific page, in this case a Dashboard.
Not have every page load at once(?) I'm still unsure on why this is, is it due to me importing the dashboard page and the element is grabbing it, not working fully, so it's just loading what the page shows?
I got an issue in my project , that I had a main component which acts as the parent component of my project inside that I had the routes for the other components and some other component which are directly imported into it like a Side Navbar Component and Login Component so which are triggered on an event button click , but when I open those components all the other components are re-rendering .
export const AppFramework = (props) => {
const [isOpen, setIsOpen] = useState(false);
const [isSideNav, setIsSideNav] = useState(false);
const OptimizedRoutes = React.memo(AppRoutes);
useEffect(() => {
console.log('AppFramework Mounted');
}, []);
// Methods For Opening and closing of Login and SideNav
const handleOpen = useCallback(() => {
setIsOpen(true);
}, [isOpen]);
const handleClose = useCallback(() => {
setIsOpen(false);
}, [isOpen]);
const openSideNav = useCallback(() => {
return setIsSideNav(true);
}, [isSideNav]);
const LoginPopBody = (
<div className="pop-window">
<Button startIcon={<Close />} onClick={handleClose}></Button>
{/* {For Fields for loggin in .........} */}
</div>
);
return (
<Router>
<HideOnScroll>
<AppBar color="default" className="app-header">
<Button startIcon={<Menu />} onClick={openSideNav}></Button> // Button To Open Side Navbar
<Button onClick={handleOpen}>Login</Button> /* Button To Open Login Popup */
</AppBar>
</HideOnScroll>
//sidenav comp passing props to open and close below
<SideNav open={isSideNav} close={setIsSideNav} />
//routes are below
<main className="main-blk">
<Suspense fallback={<div>Loading...</div>}>
<OptimizedRoutes />
</Suspense>
</main>
<Modal open={handleOpen}>{LoginPopBody} </Modal>
</Router>
);
};
export default React.memo(AppFramework);
On opening and closing of both login popup and side navbar renders every component .I tried React.memo in each component but nothing happened , I hope hooks will give a solution for this.
And one more thing while entering each input on login popup form fields also renders every components behind the login popup . what will be the solution for these issues ?
This might not be the answer you are satisfied with but most of the time these problems pop up because of the way you design/construct your components. In react planning the components is the first and in my opinion the most important thing. It can save us from a lot of trouble. In this case You need to keep the components linked but independent of each other.
I would recommend you to read https://reactjs.org/docs/thinking-in-react.html. This might help you.
Changing the state will definitely re-render the whole component. But to avoid some components to stop re-rendering or re-render on come custom state changes you can use useCallBack hook.
The following article might help.
https://kentcdodds.com/blog/usememo-and-usecallback/
You can put the other component in individual functions and use useCallback hook on those function. This way you can define on which state change should those functions be used again.
Actually the issue is resolved , actually my problem is very simple , its not a complicated problem , To open the Side Navbar and Login Component I don't need to pass a boolean value from the parent component as a Prop .
Instead of that, we can get the boolean value from the own component by a passing a boolean value to the module to be shown in my case I used Material UI's Modal and Drawer by an event like button click or any other event .
This is what I did to solve my issue . In short I made the components independent.
I have 3 pages reactjs application with a bootstrap template. I am using react-router to handle the page transitions.
So I have a index.js file containing something like:
function App() {
return(
<Router>
<Switch>
<Route path="/page1/">
<Page1 />
</Route>
<Route path="/page2">
<Page2 />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
);
}
In my index.html file, I defined some js functions to apply some effects to the pages, like a carousel and things like this. The weird thing is that when I reach page2 from clicking the link on page1 the js effects are applied, but when I refresh it the js effects are not applied...
this is my page2 file (I stripped all the unnecessary stuff for simplicity):
function Page2(){
useEffect(() => {
window.applyEffects();
})
return(
some jsx here...
)
}
am I doing something wrong here?
EDIT
I realised I forgot to add an important detail. I removed the useEffect and the call to window.applyEffects() in my component and the page renders as I would expect without the effect. If then I call window.applyEffects() from the developer console everything works fine. I suspect I should find a way to call the js function AFTER the page has been totally rendered. Is this doable?
SOLVED
I would like to thank everyone that replied and helped me in the right direction. I solved it by updating the useEffect hook like this:
useEffect(() => {
const script = document.createElement('script');
script.src = `${window.location.origin}/js/effects.js`;
script.async = true;
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
}
});
I created a file called effects.js in the js folder, and I load it by appending it to the dom every time the component loads... also I remember to remove it with the return. I leave this here hoping it could help someone in my same situation in the future!
Thank you stackoverflow community !
I saw that you are using window object inside your code. Maybe that is the root of your problem. On the official documentation it says:
Window Object The window object represents an open window in a
browser.
If a document contain frames ( tags), the browser creates one
window object for the HTML document, and one additional window object
for each frame.
...which kind of suggests that it will fire once the window is open in the browser, hence I'm not sure that it will re-fire once you refresh the page. Having the useEffect hook should fire away anything when a page refreshes because it mounts the component again.
I suggest look into how you are using the window.applyEffects(). Here's a link to the official window documentation.
It seems that you just want to run a piece of code every time page is reloaded, checking it out I found it
React | How to detect Page Refresh (F5)
and it seems what you are looking for.
in my web react project i have two class one "Menu" return the Menu for my dashboard (the links to change the pages "Home" , "messages" ....) and another one "Box" for show the pages (it's the container of my website pages ) so my question is how the page when i click button ?.
class menu(){
render(){
return(<button>click to go to home</button>) ;
}
}
class box(){
render (){
return(<Home>this is the home</Home>) ;
} }
You can create a parent component that has the page property and the setPage method.
Inside that component, render the toolbar and the pages. The toolbar should accept a prop that'll called onClickPage that should dispatch the setPage. For example:
const [page, setPage] = React.useState("dashboard");
....
<Toolbar onClickPage={page => setPage(page)} />
<Pages page={page} />
This is what's called Lifting the state up (https://reactjs.org/docs/lifting-state-up.html) I suggest you to read their docs. It's very beginners friendly.
If your main problem is to navigate between pages you can easily achieve this by using react-router.
https://reactrouter.com
I set up a minimal Gatsby page to test when Gatsby re-renders, and I found out that just clicking a regular in-route (hash) anchor link, causes a re-render.
Why is that? Is there any way to prevent it?
Here is an example page:
const SomePage = props => {
console.log('RE-RENDERING PAGE');
return (
<>
Link that should not fire re-render;
</>
);
};
import { Link } from "gatsby"
const SomePage = props => {
return (
<Link to="#foo">Link that should not fire re-render</Link>;
);
};
<Link> will render a fully accessible anchor tag with the proper href.
React re-renders a lot. Since the entire page is wrapped in a Reach Router and you're using a non-memo functional component I'm not the slightest bit surprised you're getting a console message. I was under the impression you were trying to avoid a page reload, not prop-change-based React render.
If you'd like to prevent the re-render, you can use React.memo:
const SomePage = React.memo(() => <Link to="#foo">Text</Link>)