React-router-dom Link open at the top of page - reactjs

So I am feeling pretty dum to ask this but cannot find a straight answer to it.
Do I need to give any css parameter or directly to <Link> in order for the pages on my react app open at the top?
EDIT
So refraining, everytime I click on a <Link>element at my reactJs project, the Link opens a page at the middle of the screen, not a the top.
For example. I have this component
<li ><Link to={{pathname: "/product", state: {products}}}><i className="fa fa-search"></i></Link></li>
and when I click on in, it opens a new page/component but not at the top of the page. The user needs to scroll up in order to see the top, and i would like to open new pages directly at the top!

This can be done without installing any additional libraries. You can check the official example of react-router for scroll restoration here.

You can use library react-scroll, and detect when change pathname of location, scroll to Top like this
import { animateScroll } from 'react-scroll';
useEffect(() => {
animateScroll.scrollToTop({
duration: 0
});
}, [location.pathname]);

make scrollToTop function and use it in your link tag
const scrollToTop = () => {
window.scrollTo(0, 0)
}
when user click on any link our function will make our page scroll to top.
<li onClick={scrollToTop} ><Link to={{pathname: "/product", state: {products}}}><i className="fa fa-search"></i></Link></li>

I am using the class component for my react blog. The issue got solved by adding the following method and calling it inside componentDidMount().
scrollToTop = () => {
window.scrollTo(0, 0)
}
componentDidMount() {
this.scrollToTop()
}
You can check this code is working. Live example, Blog.
If you are using a function component, then same method you can use and call it inside UseEffect().

Related

How to Redirect to New Page and Fire up the Action?

Using NextJS and Redux.
Let me briefly explain as it seems complicated without understanding the website mechanic.
My Website Buttons:
Home (Goes to homepage)
Search (Opens search menu in homepage)
Sign In (Goes to sign in page)
Imagine having 3 buttons in the navigation bar. First button goes to '/' page. Second button's function is to open up a sliding menu that is only available in page '/'. Third button takes you to '/sign-in' page. Remember the second button. So if the second button is clicked when the website is on '/' page, there is no problem with the sliding menu opening and closing. But, if lets say I am in '/sign-in' page and clicked on the sliding menu opening button, I want my website to first go to '/' page, then open up the sliding menu.
Snippet goes to the '/' page but fails to execute the next line of code.
const searchClickHandler = useCallback(() => {
if (window.location.pathname !== '/') {
router.push('/');
}
dispatch(toggleFilterMenu());
}, [dispatch, router]);
I tried using Thunk principle inside Redux but as you may know useRouter hook cannot be used inside a Redux file. I tried async await keywords but dispatch method gives warning saying that I cannot use await for dispatch method.
Any help would be appreciated.
You could pass some "state" in the PUSH to the "/" route and check this in the receiving component. In other words, effect a navigation to the "/" route first, and then in that component check if the search menu should be opened.
Example:
const searchClickHandler = useCallback(() => {
router.push(
{
pathname: "/",
query: { openMenu: true }
},
"/"
);
}, [dispatch, router]);
const router = useRouter();
useEffect(() => {
if (router.query.openMenu) {
dispatch(toggleFilterMenu());
}
}, [router]);
If I am understanding correctly. Then, You can use the useEffect. Hook to trigger the function that opens the sliding menu after the component has finished rendering.
import { useEffect } from 'react';
const searchClickHandler = useCallback(() => {
dispatch(toggleFilterMenu());
}, [dispatch]);
useEffect(() => {
if (window.location.path !== '/') {
router.push('/');
}
searchClickHandler();
}, [searchClickHandler, router]);
When the button is clicked, hook will be triggered and will check the and the current path, and then it's open the menu.
OK actually, I found out that both answers and my method actually works. Problem was with another action called resetSlidingMenuStates intercepts with what I want to accomplish in every new page reload... I spent 2 hours on this but now while tinkering, found out it was because of another action I put.
We can lock the this thread. Thanks.

Render a react component inside leaflet's popup created in pointToLayer of react-leaflet's GeoJSON

I'm looking for a way to render a react component (e.g. mui's Link) inside a popup created in react-leaflet's pointToLayer function of the GeoJSON component. Alternatively, invoke a function by clicking <a> or <button> in the popup.
The code I'm using now kind of works – I could redirect a user to a different URL. The problem is that I want the link inside the popup to call a function (which will change react's state, e.g. opening mui's Drawer).
import L from "leaflet";
import geoJSON from "../resources/test.json";
function callMe() {
console.log("test") //will change state
}
function featureToCircle(feature, latlng) {
const pointName = "from feature";
const popup = L.popup().setContent(`
<p>${pointName} – (${latlng.lat}, ${latlng.lng})</p>
invoke callMe()
`);
//ideally: <Link href="#" onClick={() => callMe() }>invoke callMe()</Link>
return L.circleMarker(latlng, {
color: "yellow",
})
.bindPopup(popup)
.bindTooltip(pointName);
}
export default function MyGeoJSON(props) {
return (
<GeoJSON key="whatever" data={geoJSON} pointToLayer={featureToCircle} />
);
}
I tried with ReactDOMServer.renderToString – unfortunately, the onClick doesn't work with this approach.
I'm also aware that I could replace GeoJSON with separate tags, like here, and it should work. I treat it as the last resort, though, and would rather use GeoJSON, to avoid replicating its functionality.

How to programmatically close bootstrap 5 offcanvas in Next Js

I use using bootstrap 5 in my NextJs app my installing like this:
npm install bootstrap and imported the necessary files into my project via _app.js like this:
import 'bootstrap/dist/css/bootstrap.css'
...
useEffect(() => {
import("bootstrap/dist/js/bootstrap");
}, []);
Now the problem is that when I open the offcanvas modal and click a link from there, the offcanvas stays open after the page changes, instead of closing. How do I programmatically close the offcanvas when the pathname changes and only when the offcanvas is active. Thank you
NB: I am not using react-bootstrap
Import like this:-
useEffect(() => {
import("bootstrap/dist/js/bootstrap.bundle");
}, []);
Recently I ran into the same problem, but here is how I got things working.
First of I do not think you are importing bootstrap in to your nextjs app the right way, but what works work. However I think you should import bootstrap into your nextjs app this way.
useEffect(() => {
typeof document !== undefined
? require("bootstrap/dist/js/bootstrap")
: null;
}, []);
I don't want to make this too long, so lets dive straight into creating the solution. First you have to create a custom function to close the offCanvas when you click your link.
const topicRef = useRef(null);
const closeOffCanvas = (event) => {
event.stopPropagation();
const bootstrap = require("bootstrap/dist/js/bootstrap");
var myOffcanvas = topicRef.current;
var bsOffcanvas = bootstrap.Offcanvas.getInstance(myOffcanvas);
bsOffcanvas.hide();
};
Now create your link like so and call the function we just created
<Link href={`/article/18004/close-bootstrap-5-offcanvas-in-next-js`} passHref>
<a href="#" onClick={closeOffCanvas}>navigate to page then close offCanvas</a>
</Link>
I hope this helps you

React Renders at the bottom of my component! no the top

when i click on one of the Links in the mobile view, it renders a new component for the product details page.
However the rendered view always starts at the bottom ..
how can i change this to always display the new component from the top ??
You can try this :
componentDidMount() {
window.scrollTo(0, 0)
}
for stateless component with the help of hooks you can achieve this by doing:
useEffect(() => {
window.scrollTo(0,0);
}, [])

react-router redirect to a different domain url

I am using react-router for client side routing. I have a button and when some one clicks the button, I want to redirect the user to a different url.
For e.g I want to redirect the user to "http://www.google.com". I used navigation mixin and used this.transitionTo("https://www.google.com"). But when I do this I get this error
Invariant Violation: Cannot find a route named "https://www.google.com".
I can use window.location but is that the right way to go?
As pointed out in the comments to this answer, default way of solving this would be to use anchor element (the a tag) with href attribute that points at the destination URL that you'd like to route the user to. A button that has appearance of a button but behavior or an anchor is pretty much a web anti-pattern. See more info in this answer: https://stackoverflow.com/a/1667512/1460905.
That said, there certainly is a potential scenario when a web app needs to perform some action and only then redirect the user. In this case, if primary action the user takes is submitting some data or really performing an action, and redirect is more of a side-effect, then the original question is valid.
In this case, why not use location property of window object? It even provides a nice functional method to go to external location. See the ref.
So, if you have a component, say
class Button extends Component {
render() {
return (
<button onClick={this.handleClick.bind(this)} />
);
}
}
then add handleClick that would make the component look like
class Button extends Component {
handleClick() {
// do something meaningful, Promises, if/else, whatever, and then
window.location.assign('http://github.com');
}
render() {
return (
<button onClick={this.handleClick.bind(this)} />
);
}
}
No need to import window since it's global. Should work perfectly in any modern browser.
Also, if you have a component that is declared as a function, you may possibly use the effect hook to change location when state changes, like
const Button = () => {
const [clicked, setClicked] = useState(false);
useEffect(() => {
if (clicked) {
// do something meaningful, Promises, if/else, whatever, and then
window.location.assign('http://github.com');
}
});
return (
<button onClick={() => setClicked(true)}></button>
);
};
You don't need react-router for external links, you can use regular link elements (i.e. <a href="..."/>) just fine.
You only need react-router when you have internal navigation (i.e. from component to component) for which the browser's URL bar should make it look like your app is actually switching "real" URLs.
Edit because people seem to think you can't use an <a href="..." if you need to "do work first", an example of doing exactly that:
render() {
return <a href={settings.externalLocation} onClick={evt => this.leave(evt)}/>
}
async leave(evt) {
if (this.state.finalized) return;
evt.preventDefault();
// Do whatever you need to do, but do it quickly, meaning that if you need to do
// various things, do them all in parallel instead of running them one by one:
await Promise.all([
utils.doAllTheMetrics(),
user.logOutUser(),
store.cleanUp(),
somelib.whatever(),
]);
// done, let's leave.
this.setState({ finalized: true }), () => evt.target.click());
}
And that's it: when you click the link (that you styled to look like a button because that's what CSS is for) React checks if it can safely navigate away as a state check.
If it can, it lets that happen.
If it can't:
it prevents the navigation of occurring via preventDefault(),
does whatever work it needs to do, and then
marks itself as "it is safe to leave now", then retriggers the link.
You can try and create a link element and click it from code. This work for me
const navigateUrl = (url) => {
let element = document.createElement('a');
if(url.startsWith('http://') || url.startsWith('https://')){
element.href = url;
} else{
element.href = 'http://' + url;
}
element.click();
}
As pointed by #Mike 'Pomax' Kamermans, you can just use to navigate to external link.
I usually do it this way, with is-internal-link
import React from 'react'
import { Link as ReactRouterLink} from 'react-router-dom'
import { isInternalLink } from 'is-internal-link'
const Link = ({ children, to, activeClassName, ...other }) => {
if (isInternalLink(to)) {
return (
<ReactRouterLink to={to} activeClassName={activeClassName} {...other}>
{children}
</ReactRouterLink>
)
}
return (
<a href={to} target="_blank" {...other}>
{children}
</a>
)
}
export default Link
Disclaimer: I am the author of this is-internal-link
I had the same issue and my research into the issue uncovered that I could simply use an "a href" tag. If using target="_blank" you should write your link this...
Your Link
I couldn't find a simple way to do that with React Router. As #Mike wrote you should use anchor (<a> tags) when sending the user to external site.
I created a custom <Link> component to dynamically decide whether to render a React-Router <Link> or regular <a> tag.
import * as React from "react";
import {Link, LinkProps} from "react-router-dom";
const ReloadableLink = (props: LinkProps & { forceReload?: boolean }) => {
const {forceReload, ...linkProps} = props;
if (forceReload)
return <a {...linkProps} href={String(props.to)}/>;
else
return <Link {...linkProps}>
{props.children}
</Link>
};
export default ReloadableLink;

Resources