Navigate away from react-router? - javascript

My React app is currently nested inside of a Spring app, which means my routing is mixed. For example, /route/1 is handled by react-router, but /route/1/details is not.
I have a component which receives a destination URL from the server as props. Some destinations are inside the router and others are outside. In an attempt to safely use <Link /> in place of <a />, I have the following catch-all route handler:
{
path: '*',
onEnter({location}) {
window.location.href = location.pathname;
}
}
This works to get me out of react-router and back to Spring; however, it breaks the back button. Pressing back from here cycles through the URL history without ever reloading the page. (The history is all routes handled by react-router.)
Am I missing something obvious here? I think I want back to force a reload, but I'm not sure how. (I see that this is sort of an XY-problem; I'm open to suggestions for different ways of approaching the problem.)
I recognize this is not an ideal solution; it is one step in a migration plan.

Related

Prevent navigation to certain pages/routes

I have a Next.js (fix may not necessarily have anything to do with Next.js) app that I want to limit some navigation. This page in the Next.js docs mentions "you should guard against navigation to routes you do not want programmatically", but I'm unsure how to do this. Let's say I have the following pages:
/bikes
/boats
/cars
and I only want to allow a user to see /bikes. How would I be able to do this. I'm able to redirect from an undesired page to an acceptable page, but only after the undesired page loads. Is there a way to redirect before this (maybe by changing the URL as soon as it is changed)?
I appreciate that this is an old question, however, I wish I had known this answer to it earlier than I did, so I would like to answer it for the record.
Our next.js app had a relatively complex set of permissions associated with accessing each page (with the ability to access the page, or different data presented on it) based on the authentication status of a user as well as the authorization scopes granted to them.
The solution that we used was the to return a redirect from getServerSideProps(). Normally one would return something like the following:
const getServerSideProps = (context) => {
return {
props: {
myProp: 1
}
};
}
However, it is also possible to return a redirect. This redirect is performed on the server side prior to the page content being sent to the browser:
const getServerSideProps = (context) => {
return {
redirect: '/login'
};
}
This is relatively new functionality - it was only pulled in towards the end of last year, and there isn't much documentation for it anywhere, but it perfectly serves this use case.

How to work with Authentication in Framework7 Vue

I am using the latest Framework7 Vue Webpack starter pack.
My default page ('/') is a login page. My plan was to run a xhr request as soon as any page in the app is requested.
So I tried putting the isLoggedIn() call in the onF7Ready(f7). If logged in I thought I would use this to take the user to the home screen - self.$f7router.navigate('/home/'); else I would take the user to the Login page. Then I learnt the $f7router is only accessible in the Route Components.
Then I thought I will put the isLoggedIn() check in each and every page's pageInit(). So I tried putting that code in the login.vue file in
on: {
pageInit(e) {
The $f7router is available here but the self.$f7router.navigate('/home/'); does not work. The same self.$f7router.navigate('/home/'); however does work if I use it in one of the dummy methods in the same login.vue file.
Even if the above code did work, there must be a better way of checking if a user is logged in and then do things in a much better way then I am doing. All my routes except for the ('/') require authentication.
Can anyone tell me how I should approach this very standard issue? Thanks a lot.
I found that the self.$f7router.navigate is not available in the pageInit(), however, it is available in the pageBeforeIn() and other functions that follows the pageInit().
Sidenote: I found pageInit() to be quite dangerous for this particular use case because everytime you navigate to this page the page is going to run the AJAX request not just when the App is first accessed.

Getting initial state using HTML5 history api

Everything I've been searching for is just a tutorial how to use pushState, replaceState, history.state, etc. Those concepts are simple but one thing I'm wondering how people solve is how to know what the initial state is.
Say you SPA is hosted at https://example.com/en-us/myapp/. Go there and your home page of the app is loaded, click around and it does a pushState to see you to https://example.com/en-us/myapp/get/users. Great, now you see a list of users and thanks to the history api, it wasn't an actual page load.
But now let's pretend a user had that https://example.com/en-us/myapp/get/users state bookmarked and the started the app off at this URL. Ok, so your server listens to that and serves up the app. My question is, how do you know that get/users is the current state and you need to show the associated view? Do you just know that your app is hosted at https://example.com/en-us/myapp/ and so you get whatever is after that to know?
Something like this:
function getState (uri) {
return uri.match(/^https:\/{2}(?:w{3}\.)?example.com\/en-us\/myapp\/?(.*)/i)[1];
}
var state = getState(location.href);
and if state is falsey then load the initial view, otherwise handle the state and show the list of users when state === 'get/users'?
Yes, that is quite right. However, you could try using location.pathname to fetch the state, so that your regex does not need to include the domain name.
For example:
function getState (uri){
var path = uri.split("myapp", 2)[1]; // This will split the pathname after 'myapp'
console.log(path) // Just for debugging purposes
// Now we can decide what to do with the path (i.e. "/get/users")
// For example, we can use a switch or a simple if statement
if (path === '/get/users'){
return true
} else {
return false
}
}
var state = getState(location.pathname);
That is just a simple example of a router. You can now try building your very own router for your SPA. Also, there are many libraries out there for you to use if you would like a different approach. You can take a look at these ones if you would like.
navigo
router.js
Also, if you are using a framework to build your SPA, they often have their own routing ability built in. These are just some of the many frameworks that have routers built in. (Sorry, I've <10 reputation so I'm not allowed more than two links).
Vue.js — vuejs.org/v2/guide/routing.html
Mithril.js — mithril.js.org/#routing
Ember.js — guides.emberjs.com/v2.13.0/routing/
Of course, it is ultimately your choice which to use. You could expand upon the example I've provided, by simply implementing a switch for different links/pages in your SPA. I wish you the best with your app!

How to programmatically navigate with preact-router?

I'm trying to figure out how to structure the frontend part of a web application using typescript, preact and preact-router. I've come a long way but I still need to figure out how to programmatically navigate (redirect) with preact-router. I can do history.replaceState(null, null, '/#/redirectedUrl');, but while that changes the URL in the location bar, preact-router doesn't route to the new URL.
What is the preferred way to programmatically navigate when using preact-router?
Importing the function route from 'preact-router' is the way to go:
import { route } from 'preact-router';
route('/url/to/rout/to');
You can do it in two ways based on your need
import { route } from 'preact-router';
route('url');
This will create a pushState in the history (i.e.,) it will create a new entry for this url
import { route } from 'preact-router';
route('url', true);
This will create a replaceState in the history (i.e.,) this will replace the current page url entry in the history with the url you will be routing to. You can make use of this in cases like, when routing from login screen to your home/dashbaord screen, where on click of browser back button, you don't want user to go back to login screen once the user has been logged in (thus replacing the login entry with your dashbaord entry).

What's the logic behind how React Router processes onEnter?

react-router has some docs on how onEnter/onLeave are handled, but I don't understand why traversing up the tree would not cause onEnter to be triggered?
For example, if you have the following routes:
/
/profile
/profile/:username
And navigated from / to /profile to /profile/boogers, onEnter would be triggered 3 times. But if you navigate to / from /profile or /profile/boogers, it's not triggered? I would expect that entering a new path with always trigger an onEnter event because you're going to a new url path?
Thanks for your time!
Related to this issue as well.
The routes are considered hierarchical. When you first navigate to /profile onEnter would be triggered on both /profile and /. When you then navigate from /profile to /, no onEnter is triggered because it is considered that you were already within that parent route.
So, I think that's technically the answer, but I also think it's dumb, IMHO. It does indeed leave you with some serious flaws, which the OP already pointed out in the linked github issue on react-router.
Related is the fact if you navigate from /users/a to /users/b, there is not a hook for that at all. Your only option to implement componentWillReceiveProps and check to see if userId has changed. Poor separation of concerns. More info: https://github.com/reactjs/react-router/issues/2547

Categories

Resources