How do I refresh current page in Gatsby? - reactjs

I have a menu with links to different pages, but when I click on the link to the page I'm already on, literally nothing happens. I want the page to rerender as if the user clicked in from another page.
I've tried
navigate('/temp')
navigate(link, { replace: true })
but it's not working.

The short answer is that you can't refresh the same page using #reach/router (from React, and Gatsby extends from it). This is because the location is the same so for the internal routing, nothing changes hence the refresh is not forced.
The easiest way to achieve it is by using the old-fashioned window.location.reload(). This will refresh the full page, forcing the components to be rendered again.
You can follow this GitHub thread for further information. As you can see, it can be achieved by diving into history.pushState and in other tricky ways but it always ends in a headache, it's not recommended since it's not the purpose of the #reach/router if it thrives will be with multiple caveats.
For standard internal navigation between pages, use <Link> component rather than navigate.

Related

Separate pages vs updating components on the same page

So I am just wondering if there are any common practices or basic guidelines as to when you should create separate pages vs just updating the components on the current page when using React? I tried to look online and could not find anything.
There are some scenarios in which you need your data or some state persisted, just some update in the UI, like Atlassian Login page.
When you write your email, it changes the route and changes some css (changes password field display from none to block).
Or in Jira next gen, there are tasks, if you click on one of the tasks in a scrum board, the page component is the same, but it brings up a modal component showing up the details of that task.
Why different routes? cause you can share the link and whenever someone navigates to that route, it brings up the page with the same UI that you saw when you copied the link.
Otherwise it's a cleaner approach to handle navigation using separate pages. So it's totally up to you and the kind of UI/UX design.

Block page change

I have a problem with blocking page changes in the application. The application is written in react and installed in liferay (CMS). It wants to keep the user on the payment intermediary selection screen. Unfortunately, the methods I know do not work properly. Blocking on the "beforeunload" event only blocks the closing of the page or its refresh (I'm only interested in closing the tab, but it is an additional condition). Blocking the website by react router doesn't work properly either. The prompt component works only within the scope of the added page, and no longer works in the navigation created on liferay. This is the same for useHistory (history.block('msg')), because it works just like the prompt component. I also tried to get this effect with other events, unfortunately to no avail. Does anyone have an idea to solve this problem? Thank you in advance.
I'm not aware about Liferay navigation behavior but I can see two resolutions:
you could go on using react router to block the transition to another route:
You could find a full example on the official docs (https://reactrouter.com/web/example/preventing-transitions).
<Prompt
when={isBlocking}
message={location =>
`Are you sure you want to go to ${location.pathname}`
}
/>
if there are parts of your application not handled by react-router you could rely on some event from history, like the one described here:
https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate
A popstate event is dispatched to the window each time the active history entry changes between two history entries for the same document.

Gatsby navigation with query parameters do hard refresh and lose the parameters

I have private pages behind a login page, if you try to reach a page the first you'll face is a redirect to the Login page and once you're logged successfully you will be redirected to the page you ask for, for example.
https://example.com/one-of-the-private-pages
redirect to
https://example.com/login
then redirect to
https://example.com/one-of-the-private-pages
the redirect is with the navigate utils from Gatsby
All this Logic is working as expected but the problem is when I need query parameters
https://example.com/one-of-the-private-pages?param1='example'
In this case, the behavior is:
Redirect to the Login page
After login
navigate(https://example.com/one-of-the-private-pages?param1='example')
then I can see a blink in the page with the parameter and a hard refresh
Finally, my URL is:
https://example.com/one-of-the-private-pages
This only happens after building to production in development mode everything works as respected
Note: I try deleting all the content on the page actually only has a div and an h1 component.
Gatsby, extends from #reach/router (from React) so it follows the behavior of it. It's intended to use only for internal navigation and, by default, does not support hashed URLs nor parameters, as the docs points:
Neither <Link> nor navigate can be used for in-route navigation with a
hash or query parameter. If you need this behavior, you should either
use an anchor tag or import the #reach/router package—which Gatsby
already depends upon—to make use of its navigate function, like so:
That's why your page blinks before losing the parameters. Don't focus on the gatsby develop/gatsby build, they have different behaviors, treat and compile the code differently and, that doesn't mean that your code has something wrong and it has stopped working in one environment, it's just that Gatsby doesn't support it.
Said that, at this point, you have two options:
Use the #reach/router dependency directly, as the documentation suggests:
import { navigate } from '#reach/router';
...
onClick = () => {
navigate('#some-link');
// OR
navigate('?foo=bar');
}
Note the import { navigate } from '#reach/router'; (not from Gatsby)
Using window.location redirection to get the parameters (manipulate them as you wish) and redirect the user accordingly.
Additionally, try using partial routes instead of absolute ones, since the internal navigation works better in that scenario, like:
navigate(/one-of-the-private-pages?param1='example')
I just solve my problem, I was using the full URL to navigate
Wrong:
navigate(https://example.com/one-of-the-private-pages?param1='example')
Correct:
navigate(/one-of-the-private-pages?param1='example')

Difference between React Router Link and history.push?

While I was using Link in React Router and history.push method,
I realized I have used those two method without proper knowledge.
I have used Link tag makes user possible to go to another component, and used history.push to make back button available.
But hard to tell the difference except history method stacks a trace.
What is the difference between Link and history.push besides I have mentioned above and how to use them properly?
With the Link you can navigate to another "page" by wrapping it for example a button and do the redirect when clicking. Mostly this is what you probably want to do.
But in some cases you want to navigate to another "page" programatically. For example when something changes in your app that has nothing to do with clicking on a button or link.
So you can use history.push to change the url programmatically without the need to click on a button or a link.
I hope this clears it for you

Links very slow to display 'large' components

I am working on a React app, and within it there is a page with a lot of graphs and large list component, which takes some time to load (performance dependant). This is fine for now, but the issue comes from the following:
at the first render, there is an API call (App wide as different pages use the same data). A loading spinner shows while the API data is fetched
Once the data is fetched, it is Redux manages the state, and each component just takes what it needs from there (no more loading).
My issue is that when I navigate between pages trough links (react-router), after I click on the link it takes a while for the page to show and the menu to update the current page. None of the state data has changed in that timeframe, so I assumed a PureComponent would prevent re-render, but it doesn't work.
Is there any way to not re-render the page? I would expect to click on a link an immediately see the page that was already loaded before.
Sorry if the question is obvious, I got quite confused while researching this, with cold splitting, lazy loading, etc. which seems to be more about initial load vs. navigation?
If you have a large component dataset to mount and your state does not changes or affects re-renders you could prevent component from unmounting entirely.
If you are using react-router you can rely on setRouteLeaveHook.
If your unmount depends on conditional rendering, it is easier as you can hide your component in various way, including css display:none
There are several ways you can do this
The first one would be to not unmount the component, just hide it with CSS and display: none, but that's a shit solution if you ask me, since you'll still have the component in the DOM.
Another solution that you can use is the one that the guys from the Facebook team used when creating the official website for React. Once you hover over the link to the page, send a request to prefetch the data for that page. So, before the user even clicked, you will have the request already sent.
Another solution you can use is to cache the data. If you are not worried about users with older browsers waiting a bit for the component to load again. You can keep the data for the component in localStorage, then, when you are about to mount the component, check if the data is already in localStorage if it's there, just render the component, if not, just grab the data again.
A combination of the first and the second option would make your component pretty much always instantly render.

Resources