NextJs Link causes Error: Loading initial props cancelled - javascript

I have nextjs 13 app and I have navbar component with some Nextjs links. After pressing the link and the page starts loading if you click the same link fast some times it throws this error: Error: Loading initial props cancelled.
What I did:
//navbar.ts
const [loadingPath, setLoadingPath] = useState()
useEffect(() => {
Router.events.on('routeChangeComplete', () => setLoadingPath(undefined))
}, [])
const onClickExample= (e) => {
e.preventDefault()
setLoadingPath('/example')
if (loadingPath === '/example' || router.asPath === '/example') return
router.push('/example')
}
//jsx
<Link href="/example" onClick={onClickExample}>Go to Example</Link > // Nextjs Link
There are some discussians like this github issue. It happens on Nextjs 12 too according comments around the net.
This is common user behavior and it's weird to throws such errors.
How do you handle it? Any elegant solution?

I don't see any reason to use onClick in your <Link> here the property href="/example" will make you navigate to /example.
and if you are doing this just to prevent the error then what you are trying to do will not help :
setLoadingPath('/example')
if (loadingPath === '/example')
makes no sens, the loadingPath state will not be updated untill the next render.
This is happening when you try to navigate to another page while the current one is still loading, usually because of a slow connection there are some althernatives like :
const [navigation,setNavigation] = useState('')
//...
const onClickExample = (e) => {
e.preventDefault();
setNavigation("/example"); // when the user clicks you update 'navigation' to the wanted URL to trigger a render
};
//...
useEffect(() => {
if (navigation !== "") { // prevent navigation for the first render
setTimeout(() => {
router.push(navigation); // when the component finishes rendering useEffect runs because navigation is updated then navigate to the wanted URL
}, "500");
}
}, [navigation]);
But you cannot do this with <Link> because it requires href so it will navigate to the given path anyway.
<a onClick={onClickExample}>Go to Example</a>
Try to do it without setTimeout maybe it works for you. In my case it was happening only in development.

Related

How to handle browser forward and back button in react-router-dom v6

I do not want a user to click browser back button and forward button from my page because my page loads stored sessions every time. If user is clicking on these buttons then i simply want him to navigate to the homepage.
For security purpose, sessions are being maintained by the backend APIs so if user will fluctuate on browser's forward and back buttons then it will cause session disruption.
I have searched everywhere and tried lots of things but no solution is compatible with the v6 of react-router-dom. There must be solution for this. Please help me out in getting the same.
this was my question recently. I searched a lot but have nothing found to do this work with react-router v6. but you can handle browser back and forward buttons using window 'popstate' event. I wrote a hook for connecting, detect and handle this event(useBackButton):
import { useEffect, useState } from "react";
const useBackButton = (callback) => {
const [isBack, setIsBack] = useState(false);
const handleEvent = () => {
setIsBack(true);
callback();
window.history.go(1);
};
useEffect(() => {
window.addEventListener("popstate", handleEvent);
return () => window.removeEventListener("popstate", handleEvent);
});
return isBack;
};
export default useBackButton;
you can write your function that does your desired work and send it to this hook. then call this hook in every component that you want.

Element of a screen still found by getByTestID after navigating on another screen

I hope I am not spamming too much... Actually, I deleted my previous questions to make this one and keep it small and up to the point.
I have a react native application built with expo with a Home screen with one button. Using a stack navigator, this button can enable users to access Screen1. I want to test the following scenario, using jest and #testing-library/react-native :
When the user clicks on the "go to screen1" button, he is sent to Screen1.
So I did this :
it(
'should take user to Screen1 when go-to-screen1 button is pressed',
async () => {
const navigate = jest.fn();
const { getByTestId } = render(<HomeScreen navigation={{ navigate }} />);
fireEvent.press(getByTestId('go-to-screen1-btn'));
waitFor(() => expect(getByTestId('screen1')).toBeTruthy());
},
);
This test succeeds.
But this one succeeds also :
it(
'should take user to Screen1 when go-to-screen1 button is pressed',
async () => {
const navigate = jest.fn();
const { getByTestId } = render(<HomeScreen navigation={{ navigate }} />);
fireEvent.press(getByTestId('go-to-screen1-btn'));
waitFor(() => expect(getByTestId('go-to-screen1-btn')).toBeTruthy());
},
);
Like if the elements on the first page still exists whereas we have moved on another page...
The waitFor is in order to wait for the page change, I tried to remove it but the first test fails if it is removed.
Here is a github repo with the code I describe.
Does someone have an idea ?
Thanks in advance for any help !

Gatsby - location.state 'Cannot read properties of null'

When I navigate from /pageA to /pageB I am passing a prop through Gatsby's Link to render UI information on PageB that I need from PageA.
If the user goes through the flow properly then the application works as expected. The problem happens when the user manually jumps to /pageB from a different page (i.e: changing url from /home to /pageB)
The navigation library that I'm using is gatsby-plugin-transition-link and I am passing the props following the documentation like so
<Link
to={'/pageB'}
state={{ fromPageA: true }}
>
My initial idea was if the prop returned null, then navigate back to the previous page cause then we know it didn't come from the correct page.
useEffect(() => {
console.log(location.state.fromPageA);
if (location.state.fromPageA === null) {
navigate('/pageA')
}
}, []);
The problem is that I can't even check for that because if I console.log it and it's null it immediately crashes my application with the error
Cannot read properties of null (reading 'fromPageA')
I think what is breaking your current code is the console.log validation, not the if statement. This should work:
useEffect(() => {
if (location?.state?.fromPageA === null) {
navigate('/pageA')
}
}, []);
If you are not using the optional chaining, you can do:
useEffect(() => {
if (location){
if(location.state){
if(!location.state.fromPageA){
navigate('/pageA')
}
}
}
}, []);
Assuming you are destructuring the location as props in the component constructor. Otherwise, use props.location.

react-native navigation false route params in navigation listener

I am using react native navigation and have two tabs. One of them has a list of entites, the other has a form to submit entities. When ever a new entity is submitted, I'd like to refresh the first tab to be sure, the newest data gets loaded.
I navigate to the first tab like this:
navigation?.navigate('Main', {refresh: true});
This props gets saved as follows:
let {refresh} = route.params;
To check, if the screen needs to refresh, I added a listener in useEffect() like this:
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () =>{
if(refresh){
doRefresh()
}
})
}, [])
Unfortunately, neither "refresh" nor "route.params" directly is ever true inside the listener. Passing the param works, because I took a closer look at the var and it gets true, whenever I submit.
Do I need to access the route.params inside a navigation listener in another way?
Thanks and hit me up, if you need more information on this
The issue is that your useEffect only runs once as your dependencies array [] is empty, and therefore your listener only receives the initial value of refresh.
You need to pass refresh as a dependency to useEffect, and I don't think you even need the focus listener in your case so you would end up with this:
useEffect(() => {
if (refresh) {
doRefresh()
}
}, [refresh])
const onPressCountry = (item,index) => {
navigation.push('SignUp2', {selectedCountryId:item?.countryID, selectedCountryName: item?.name} )
}
use navigation.push instead of navigation.navigate

hash from url gets removed before page loads

I'm trying to capture hash from url such as this https://examplesite.com/page#time=1/12/2019&index=12344&access_token=JWT but before I get the chance to capture it, the access_token in that url gets removed and upon the site load, I can't capture the hash using window.location.hash
My example is inside a React functional component, using React hooks:
const watchHash = () => {
if (window.location.hash.includes('access_token')) {
console.log(window.location.hash);
}
};
useEffect(() => {
window.addEventListener('hashchange', watchHash);
watchHash();
return window.removeEventListener('hashchange', watchHash);
}, []);
The above code watches the hash and only prints the url that doesn't includes access_token, such as this #time=1/12/2019&index=12344,
event if try to console.log(window.location.hash) outside the hook and at the top of the component itself.
I can't seem to figure out why it's doing this, help appreciated.

Categories