Double forward slash in url breaks router - javascript

This is my React router:
function redirect(nextState, replaceState) {
replaceState({ nextPathName: nextState.location.pathname }, '/')
}
const routes = (
<Route component={App}>
<Route path="/" component={Lead}/>
<Route path="*" onEnter={redirect}/>
</Route>
);
export default routes;
Every route entered except for '/' gets redirected to '/'
The problem is: if the user enters mywebsite.com//
The server will not be able to serve static assets and the website will appear without JS nor CSS
How to solve that?

Add This At The End of <Switch> before <Route path="*" >
<Redirect from="//*" to="/*" />

Related

React Router v6 always render "/"

I'm trying to implement router in react-create-app but it always render "/" and showing Home or SignIn page. How can I solve this?
function AppRouter({ isLoggedIn, user }) {
return(
<Router>
<Routes>
<Route path="/profile" element={<Profile />} />
<Route path="/signUp" element={<SignUp />} />
{isLoggedIn
? <Route exact path={"/"} element={<Home user={user}/>} />
: <Route exact path={"/"} element={<SignIn />} />
}
</Routes>
</Router>
)
}
It seems you have a slight misunderstanding of how the HashRouter works with the UI.
import { HashRouter as Router, Route, Routes } from "react-router-dom";
import Profile from "./Profile";
import SignUp from "./SignUp";
import Home from "./Home";
export default function App() {
return (
<Router>
<Routes>
<Route path="/profile" element={<Profile />} />
<Route path="/signUp" element={<SignUp />} />
<Route path="/" element={<Home />} />
</Routes>
</Router>
);
}
The HashRouter handles routing with a URL hash value, i.e. everything after the "#" in the URL. If you are trying to render your app and access "<domain>/" instead of "<domain>/#/" the routing won't work.
For example in your running codesandbox demo, the base URL is "https://5p7hff.csb.app/". At this base URL the hash router isn't really working, and you should really be accessing "https://5p7hff.csb.app/#/" instead so the hash router is loaded and the app's internal routing can work.
From "https://5p7hff.csb.app/#/" you should be to then navigate to any of your routes, i.e. "https://5p7hff.csb.app/#/profile" and https://5p7hff.csb.app/#/signUp".
If you switch to a different router, like the BrowserRouter then the "/#/" is no longer used, the router and routes render from "/" where the app is running from. The routes would be "https://5p7hff.csb.app/", "https://5p7hff.csb.app/profile", and "https://5p7hff.csb.app/signUp".

Nested <Route> components are not rendering properly in react-redux-router [duplicate]

I am trying to group some of my routes together with React Router v4 to clean up some of my components. For now I just want to have my non logged in routes group together and my admin routes grouped together but the following doens't work.
main.js
const Main = () => {
return (
<main>
<Switch>
<Route exact path='/' component={Public} />
<Route path='/admin' component={Admin} />
</Switch>
</main>
);
};
export default Main;
public.js
const Public = () => {
return (
<Switch>
<Route exact path='/' component={Greeting} />
<Route path='/signup' component={SignupPage} />
<Route path='/login' component={LoginPage} />
</Switch>
);
};
export default Public;
The Greeting component shows at "localhost:3000/", but the SignupPage component does not show at "localhost:3000/signup" and the Login component doesn't show at "localhost:3000/signup". Looking at the React Dev Tools these two routes return Null.
The reason is very obvious. for your route in main.js, you have specified the Route path of Public component with exact exact path='/' and then in the Public component you are matching for the other Routes. So if the route path is /signup, at first the path is not exact so Public component is not rendered and hence no subRoutes will.
Change your route configuration to the following
main.js
const Main = () => {
return (
<main>
<Switch>
<Route path='/' component={Public} />
<Route path='/admin' component={Admin} />
</Switch>
</main>
);
};
export default Main
public.js
const Public = () => {
return (
<Switch>
<Route exact path='/' component={Greeting} />
<Route path='/signup' component={SignupPage} />
<Route path='/login' component={LoginPage} />
</Switch>
);
};
Also when you are specifying the nested routes these should be relative to the parent Route, for instance if the parent route is /home and then in the child Route you wish to write /dashboard . It should be written like
<Route path="/home/dashboard" component={Dashboard}
or even better
<Route path={`${this.props.match.path}/dashboard`} component={Dashboard}

React router get currently active segment as param

I have following router configuration
<Router history={history}>
<Route path="/" component={ReviewWizard}>
<IndexRoute component={Administrative}/>
<Route path="Administrative" component=Administrative}>
<Route path="/Administrative/:itemId" component={AdministrativeItem}/>
</Route>
<Route path="Offense" component={Offense}/>
</Route>
</Router>
I'm trying to get currently active route segment (ie Administrative or Offense).
Is there a way to do something like this? ie route constraints
<Router history={history}>
<Route path="/:segment" component={ReviewWizard}>
<IndexRoute component={Administrative}/>
<Route path="/:segment=Administrative/:itemId" component={Administrative}>
<Route path="/Administrative/:itemId" component={AdministrativeItem}/>
</Route>
<Route path="/:segment=Offense" component={Offense}/>
</Route>
</Router>
If not, what is best practice to get the current active route segment? I don't like this.context.router.routes[1].path
First off I would recommend the following router config, as it seems that it's what you're aiming for:
<Router history={history}>
<Route path="/" component={ReviewWizard}>
<!-- whenever we hit '/' we redirect to '/Administrative' -->
<IndexRedirect path="/Administrative"/>
<!-- Renders ReviewWizard <- Administrative -->
<Route path="/Administrative" component={Administrative}>
<!-- Renders ReviewWizard <- Administrative <- AdministrativeItem -->
<Route path="/Administrative/:itemId" component={AdministrativeItem}/>
</Route>
<!-- Renders ReviewWizard <- Offense -->
<Route path="/Offense" component={Offense}/>
</Route>
</Router>
As for detecting the currently active route (or if a route fragment is active), I would recommend using the router.isActive -method. Simply do something like this:
if (router.isActive('/Administrative')) {
doSomething()
} else if (router.isActive('/Offense')) {
doSomethingElse()
}
For something more declarative, I recommend just using the location object that react-router injects into each component it manages:
const { location: { pathname } } = this.props
const [ activeSegment ] = pathname.slice(1).split('/')
Hope these help!

Add authoriazation to react routers

I have defined routers in my react application. I have a 3 pages in my application. After the user successfully logs in, it is taken to the next screens. Flow is working fine. But there is a problem. When I directly enter the url for other pages in my application, it loads that page regardless of whether user logged in or not. I want to add a check on this. If user is not logged in then he must be redirected to the login page.
These are my routes
<Route path="/" component={LoginPage}/>
<Route path='app' component={App}>
<IndexRoute component={Home}/>
<Route path='/video-screen' component={VideoScreen}>
<IndexRoute component={TagList}/>
<Route path='/add' component={AddTags}/>
<Route path='/TagList' component={TagList}/>
<Redirect from='*' to='/'/>
</Route>
</Route>
</Router>
And this is my login component's method which checks the login credentials and take user to next page if login is successful
handleLoginButtonClick() {
var that = this;
let token;
var settings = {
"async": true,
"crossDomain": true,
"url": "https://www.backend.example.raccte.com/auth/login/",
"method": "POST",
"credentials": 'include',
"headers": {
"content-type": "application/x-www-form-urlencoded",
},
"data": {
"password": document.getElementById("password").value,
"username": document.getElementById("username").value
},
success:( response, textStatus, jQxhr )=> {
this.props.tokenAction(response.auth_token);
}
}
$.ajax(settings).done((response) => {
token = response.auth_token
console.log(token);
this.context.router.push('/app')
});
Updates
function authorize(){
if(window.localStorage.token == null){
browserHistory.push('/')
}
}
function getRoutes(store) {
return (
<Router>
<Route path="/" component={LoginPage}/>
<Route path='app' component={App} onEnter={this.authorize}>
<IndexRoute component={Home}/>
<Route path='/video-screen' component={VideoScreen}>
<IndexRoute component={TagList}/>
<Route path='/add' component={AddTags}/>
<Route path='/TagList' component={TagList}/>
<Redirect from='*' to='/'/>
</Route>
</Route>
</Router>
)
}
export default getRoutes;
gives me an error saying Uncaught ReferenceError: authorize is not defined
Routes have an onEnter functionality you can use for this. Let's say you have a function to authorize it inside the component containing the React router stuff. You could do something like this (some pseudo code here):
authorize() {
if (user is NOT authorized) browserHistory.push(login page)
}
<Route path="/" component={LoginPage}/>
<Route path='app' component={App} onEnter={this.authorize}/>
</Router>
That way even if they enter the URL straight into the browser URL bar, the onEnter function is still called, and if they aren't logged in it will redirect them to the login page.
Issue is u declared your authorize method in App component, you need to declare it in the file where you defined all routes, like this:
function authorize(){
console.log('hello');
}
<Router>
<Route path="/" component={LoginPage}/>
<Route path='app' component={App} onEnter={authorize}>
<IndexRoute component={Home}/>
<Route path='/video-screen' component={VideoScreen}>
<IndexRoute component={TagList}/>
<Route path='/add' component={AddTags}/>
<Route path='/TagList' component={TagList}/>
<Redirect from='*' to='/'/>
</Route>
</Route>
</Router>
I use Higher-Order Components for this check this exemple
RequireAuth
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
export default function (ComposedCmponent) {
class RequireAuth extends Component {
componentWillMount () {
//we need to check if user is authenticated before the component will mount
//here i check if the user is authenticated i'm using JWT authentification for this exemple, usually i use local storage to save the token and we can check the validation of the token
//If the user is not authenticated we redirect to /login
let validtoken = window.localStorage.getItem('id_token')
if (!this.props.isAuthenticated || !validtoken) {
this.context.router.push('/login')
}
}
componentWillUpdate (nexProps) {
// we need to the same as we did in componentWillMount
// in case component will update the use not authenticated
//If the user is not authenticated we redirect to /login
if (this.props.isAuthenticated !== nexProps.isAuthenticated) {
if (!nexProps.isAuthenticated) {
this.context.router.push('/login')
}
}
}
render () {
//now the user is authenticated we render the component passed by HOC component
return (
<ComposedCmponent {...this.props} />
)
}
}
and if i want secure a path i use my HOC RequireAuth in my router
<Route path='/' component={App}>
<Route path='/dashboard' component={requireAuth(Dashboard)} />
</Route>

React-router not matching on valid route

I cannot get this react router to match on second part of a path no matter what I do.
Express server is returning index.html for any URL match (I'm not getting a GET error on any URL so I assume this is fine)
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, 'index.html'));
});
Here are some examples of routes i've tried, which should be valid rules according to react router docs
Example 1 )
<Route path="test">
<IndexRoute component={Home} />
<Route path="/login" component={Login} />
</Route>
OR
<Route path="test">
<IndexRoute component={Home} />
<Route path="/login" component={Login} />
</Route>
http://localhost:3100/test = Success > Returns home component
http://localhost:3100/test/login = Fail > gives me blank screen
Example 2 )
<Route path="/login" component={Login} />
http://localhost:3100/login = Success > Returns login component
Example 3 )
<Route path="/test/login" component={Login} />
OR
<Route path="test/login" component={Login} />
http://localhost:3100/test/login = Fail > gives me blank screen
I'm using version 2.5, Any help would be much appreciated!
** Yarn dump of react router **
react-router#^2.5.0:
version "2.8.1"
resolved "https://registry.yarnpkg.com/react-router/-/react-router-2.8.1.tgz#73e9491f6ceb316d0f779829081863e378ee4ed7"
dependencies:
history "^2.1.2"
hoist-non-react-statics "^1.2.0"
invariant "^2.2.1"
loose-envify "^1.2.0"
warning "^3.0.0"
Try path="login" instead of path="/login" . The slash before path is not needed in nested routes.
<Route path="test/">
<IndexRoute component={Home} />
<Route path="login" component={Login} />
</Route>
From express documentation, app.get('/*' uses regular expression. so, '/*' work for 0 to n '/'. Try:
app.get('/.*
/.* should resolve '/' + 0 to n caractères.
Regards
I think the problem lies more with the way you are rendering your app than react-router itself, since you are not getting a route not found message but a blank screen, I suggest the following.
when you create your history object do the following
import { useRouterHistory } from 'react-router';
import createBrowserHistory from 'history/lib/createBrowserHistory';
// ========================================================
// Browser History Setup
// ========================================================
const createHistory = (basename) => {
return useRouterHistory(createBrowserHistory)({
basename: basename
})
}
const history = createHistory('/test');
Your route configuration will then look like this
<Route path="/" component={App} >
<IndexRoute component={Home} />
<Route path="login" component={Login} />
</Route>
Your App component would then look something like this
export const App extends Component = {
render() {
return(
<div class='app-container'>
{this.props.children}
</div>
)
}
}
App.propTypes = {
children: PropTypes.element.isRequired
}
export default App;
You'll then be able to access and render the component Login # /test/login

Categories

Resources