Redirect to external or internal link - react-router

I have a page in my application where backend decides where user should be redirected next. And it can be external link like 'google.com' or internal '/'. I use useNavigate hook from react-router-dom.
import { useNavigate } from "react-router-dom";
import axios from "axios";
useEffect(async () => {
await axios.get().then((response) => {
navigate(axios.redirectLink);
});
});
It perfectly works for internal links, but doesn't work for navigate('https://google.com'). Then it tries to open https://my-website/https://google.com. What might be a solution here?

There is no solution in navigating if you want a use Link tag do that else you can check this link as well
React-Router open Link in new tab
<Link to="your url" target="_blank">Test</Link>

Related

Svelte - routing , When I try entering any url I only get "No webpage was found" error

Using "svelte-routing" because I need to load a single page from lots of different urls , with the different urls serving as parameters.
For example if a client loads into my-sight/123 the sight needs to load the app.svelte component while passing 123 as a parameter.
The Problem is that whatever url I enter after the "my-sight/" I always get a "No webpage was found" page.
App.svelte:
<script script lang="ts">
import MenuGenerator from './components/MenuSections/MenuGenerator.svelte';
import { Router, Route } from 'svelte-routing';
</script>
<Router>
<Route path="/:accomodation" component={MenuGenerator} />
</Router>
MenuGenerator.svelte:
<script script lang="ts">
export let accomodation: string;
console.log('hello ', accomodation);
</script>
I've tested this on https://codesandbox.io/s/svelte-routing-forked-ztddj , just add anything after the / in the url and press enter and the same text is in the console.
Edit: We have QR codes and NFC tags, their urls are set and cannot be changed. The urls are my-sight/{qr_code} . I need routing that would redirect every possible url to home and pass in the {qr_code} as a value.
With that last edit / comment, your use case makes a whole lot more sense.
You can use window.location.pathname in the browser to identify the QR Code within the URL.
<script>
import { Router, Route } from "svelte-routing";
import Home from "./routes/Home.svelte";
import { onMount } from "svelte";
onMount(()=>{
let qr_code = window.location.pathname.substring(1); // dump leading '/'
console.log("qr_code: ", qr_code);
})
</script>
<Router>
<div class="box">
<Route path="/:id" component={Home} />
</div>
</Router>
(edit) This answer specifically address the need to" I need routing that would redirect every possible url to home and pass in the {qr_code} as a value.
It sounds now, like that is only a partial requirement. (/edit)
SOLVED !!!
I needed to uncomment a line of code in my snowpack config.
The line of code is:
//{ match: 'routes', src: '.*', dest: '/index.html' },
Tnx for the help !

Update react-router when next/router changes state

I have a Next.js app with several pages with separate pages with their own BrowserRouter from react-router-dom inside the Next app. (This is the reason for that.)
Using Link from react-router-dom works fine, the changes propagate only throughout components within the BrowserRouter, which works for our case. (When linking to a page with another BrowserRouter we use next/link, which also works fine.)
However, we are now creating a component to be shared between pages using different BrowserRouters, so I've used next/link within that shared component.
The problem with that is that the changed state of the Next router does not propagate into the BrowserRouter.
Minimal reproduction of the problem here: https://codesandbox.io/s/next-js-react-router-not-updating-uy8bj
The BrowserRouter is in components/App.js.
You can access the next/router state within the BrowserRouter as well. The least invasive fix is to push to the history of the BrowserRouter when it is out of sync with the next/router. You can do that in a component like this:
import { useEffect } from "react";
import { useRouter as useNextRouter } from "next/router";
function RouteIfStaleUrl(props) {
const nextRouter = useNextRouter();
useEffect(() => {
if (props.match.url !== nextRouter.asPath) {
props.history.push(nextRouter.asPath);
}
});
return false;
}
Then add that component to a Route inside the BrowserRouter. It is important that the route has path="*" if it is supposed to run on all routes.
<BrowserRouter>
<Route path="*" component={RouteIfStaleUrl} />
// other stuff ...
</BrowserRouter>
Forked Codesandbox with the fix: https://codesandbox.io/s/next-js-react-router-fix-updates-sug4s

React - Re-direct to a new domain

I have an app built in react and I am trying to implement re-direct where I need to redirect the user from my app base URL to a completely new domain.
Example:
React app base URL - "localhost:3001"
Redirect to - "www.google.com"
I am using react routes in my app.
ReactDOM.render(
(
If I use Redirect as above, it redirects to "http://localhost:3001/#/http:/www.google.com"
How to get rid of base URL while redirecting to a new domain?
React-route only allows redirect to other routes, you can confirm this by reading Github issue here
So the answer is NO, YOU CAN'T.
If I'm not misunderstanding your intention here, you want to redirect whatever which is not being handled by the router.
One aproach that comes to my mind as a solution:
A component-dedicated: Create a component dedicated for this route with a componentDidMount similar to this:
componentDidMount() {
window.location.assign('http://github.com');
}
As an alternative, you can catch it directly in the server and redirect there.
But definitively you need to look for an alternative solutoin due react-route does not allow redirecting to externals url
Expanding on an excellent answer by Facino La Rocca
import React, {Component} from 'react';
class DomainUrlRedirect extends Component{
componentDidMount(){
const{searchParams, pathname, url} = this.props
let uri = new URL(url);
uri.pathname = pathname
for(const paramName in searchParams){
uri.searchParams.append(paramName, searchParams[paramName])
}
window.location.assign(uri.href)
}
render(){
return(<span data-test-component="DomainUrlRedirect"></span>)
}
}
export default DomainUrlRedirect
You can leverage URL utility supported by modern browsers to construct your URL properly.
Also, don't forget that the component will still try to render. Render it as part of some other component on condition so that object that uses it does not disappear.
render(){
const{ redirectNow } = this.props;
return(<div>
<p>Important content</p>
{redirectNow &&
<DomainUrlRedirect {...url_params}/>
}
</div>)
}

Prefetch resources for async routes

Is there a way to prefetch or preload async routes? I'm exploring how to do this right now with RR2/3. The basic idea is I code split on every route but I'd like to be able to cache bundles for connected pages in a service worker before visiting that page. So what I'd like to do is have a custom <Link> that every time it's rendered, it tries to cache the resources of the page it's linked to. This would make page transitions considerably faster. What I don't know is if there's a way to emulate navigating to a route so that the resources will be fetched. Is there an API for this or some sort of tricky way to do this someone can think of?
This is what I came up. It's a component that wraps the React Router Link component and in componentDidMount (so only runs on the client not the server) check if in production (no need to run this during development) and if this is a browser that doesn't support Service Workers (this check is specific to my use case). Then manually match against the location and call any async getComponent functions.
import React from 'react'
import Link from 'react-router/lib/Link'
class GatsbyLink extends React.Component {
componentDidMount () {
// Only enable prefetching of Link resources in production and for browsers that
// don't support service workers *cough* Safari/IE *cough*.
if (process.env.NODE_ENV === 'production' && !('serviceWorker' in navigator)) {
const routes = require('my-routes')
const { createMemoryHistory } = require('history')
const matchRoutes = require('react-router/lib/matchRoutes')
const getComponents = require('react-router/lib/getComponents')
const createLocation = createMemoryHistory().createLocation
if (typeof routes !== 'undefined') {
matchRoutes([routes], createLocation(this.props.to), (error, nextState) => {
getComponents(nextState, () => console.log('loaded bundle(s) for ' + this.props.to))
})
}
}
}
render () {
return <Link {...this.props} />
}
}
module.exports = GatsbyLink
You could just do a require.ensure... section in a timeout when the Link is mounted. That should require the code split and load it up async. The timeout will ensure it get's loaded in a separate file.
I would recommend using RR4 for code splitting as I found in RR3 the async required routes get re-included and re-rendered if a child route changes. In my case, I had the componentWillMount of my routes being fired for any child route changes. e.g. Navigating from /agent/step-1 to /agent/step-2 will cause the Component for /agent to be unmounted and re-mounted.

Why my page will not change when use history.push using react-router

I have a single page application webpage...
Below is some of my code...
var createBrowserHistory = require('history/lib/createBrowserHistory');
var history = createBrowserHistory();
history.push('account/person');
When I click a button, I can see the browser's URL change to http://IP/account/person, but nothing happened, still on same page.
But if I replace url directly to http://IP/account/person by typing, the page will map to correct page.
Below is my react router config
<Router history={new createBrowserHistory()}>
<Route path='/account' component={Gift}></Route>
<Route path='/account/person' component={Person}></Route>
</Router>
Why this happened?
I think you need to import a different object to handle the programmatic routing:
https://github.com/reactjs/react-router/blob/master/docs/guides/NavigatingOutsideOfComponents.md
import { browserHistory } from 'react-router'
browserHistory.push('/account/person')