React Router path wrongly matches - javascript

I'm using React v4.2 for my app, and it seems not to be matching the correct path for the routes:
<Provider store={store}>
<BrowserRouter>
<div>
<Switch>
<Route path="/login" render={(props) => {
if (isAuthenticated()) {
return <Redirect to='/' />;
} else {
return <LoginForm {...props}/>
}
}
} />
<EnsureLoggedInContainer>
<Route exact path="/group" render={(props) => {
debugger;
return <GroupList {...props}/>
}
}/>
<Route exact path="/group/new" render={(props) => {
debugger;
return <GroupList {...props} modal={rr}/>;
}
} />
</EnsureLoggedInContainer>
</Switch>
</div>
</BrowserRouter>
</Provider>
I have some links in the app, on which I click and I redirect the client to new URL:
_onSubmit(values) {
const { history } = this.props;
this.props.createGroup(values, ({status}) => history.push('/group'));
}
I inspect the values of props.history.location.pathname and props.match.path and they don't match. Why is this happening? Why is the correct route not matched?
Update 1
The code for EnsureLoggedInContainer:
class EnsureLoggedInContainer extends Component {
componentDidMount() {
if (!isAuthenticated()) {
dispatch(setRedirectUrl(currentURL))
this.props.history.replace("/login")
}
}
render() {
if (isAuthenticated()) {
return(
<div>
<AppNavBar />
<ComponentsNavBar />
{this.props.children}
</div>
);
} else {
return <noscript />;
}
}
}
export default EnsureLoggedInContainer;
Update 2
I changed the router configuration code to the following:
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<div>
<Switch>
<Route exact path="/login" render={(props) => {
if (isAuthenticated()) {
return <Redirect to='/' />;
} else {
return <LoginForm {...props}/>
}
}
} />
<Route exact path="/register" render={(props) => {
if (isAuthenticated()) {
return <Redirect to='/' />;
} else {
return <RegisterForm {...props}/>
}
}
} />
<EnsureLoggedInContainer>
<Route exact path="/group" component={GroupList} modal={newGroupModal}/>
<Route exact path="/group/new" component={GroupList}/>
<Route component={Home} />
</EnsureLoggedInContainer>
</Switch>
</div>
</BrowserRouter>
</Provider>
, document.querySelector('.container'));
And changed the last line of EnsureLoggedInContainer to :
export default withRouter(EnsureLoggedInContainer);
But still, I get Home always being rendered, and random URLs being matched to unrelated routes (e.g. /group/new)

As per the documentation:
A match object contains information about how a matched
the URL. match objects contain the following properties:
params - (object) Key/value pairs parsed from the URL corresponding to the dynamic segments of the path
isExact - (boolean) true if the entire URL was matched (no trailing characters)
path - (string) The path pattern used to match. Useful for building nested <Route>s
url - (string) The matched portion of the URL. Useful for building nested <Link>s
while
Locations represent where the app is now, where you want it to go, or
even where it was.
so if you are on say /group/new, location.pathname will give you /group/new whereas match.path will give your the Route path defined for the component in which you log it if it is matched

I finally managed to resolve the issue by using the private route pattern.

Related

How to show error page if route is not available? [duplicate]

This question already has an answer here:
Redirect to Home page if URL not found
(1 answer)
Closed 5 months ago.
I have following implementation of React routing. How can I create Error page if path not found from routes list ?,
function App() {
return (
<div className="app-container">
<Switch>
{routes.map(({ key, path, crumbs, renderComponent }) => {
return (
<Route key={key} path={path}>
{renderComponent(crumbs)}
</Route>
)
})}
<Redirect to="/add-user" />
</Switch>
</div>
)
}
assuming its V5, It would be something as below...
Show a 404 Not found
<Route path="*">
<FourZeroFour />
</Route>
Redirect if not found
<Route path="*">
<Redirect to="/" /> // replace your home page path
</Route>
If you care, a good blog post on same ...
I think, we should to check the availability of key param. If key param was not exist, let's redirect user to Custom element 404 Page not found.
function App() {
return (
<div className="app-container">
<Switch>
{routes.map(({ key, path, crumbs, renderComponent }) => {
return (
if(key){
<Route key={key} path={path}>
{renderComponent(crumbs)}
</Route>
}
else{
<CustomElement404PageNotFound />
}
)
})}
<Redirect to="/add-user" />
</Switch>
</div>
)
}
Thank you
You can do it with put Route with path "*" append to last one.

React Router path var with other paths as well, React cant tell the difference

I am setting up react router for different link in my project but the problem is I need react router to tell the difference between a user username variable and other paths.
For example:
baseUrl/admin
baseUrl/daniel
React doesnt know the difference. I will have a list of usernames in a db and would return an error if the user doesnt exist then that means the page does not exist.
This is my code:
class App extends Component{
render(){
return (
<Router>
<Route exact path="/" render={props => (
<React.Fragment>
<h1>Hey</h1>
</React.Fragment>
)}
/>
<Route exact path="/admin" render={props => (
<React.Fragment>
<h1>admin</h1>
</React.Fragment>
)}
/>
<Route path="/:user" component={UserComponent}
/>
</Router>
);
}
}
You can use the match.url property to choose which component render, for example:
<Route path="/:user" render={props => {
if(props.match.url === '/admin') {
return (
<React.Fragment>
<h1>Hey</h1>
</React.Fragment>
)
} else return (<UserComponent {...props} />)
}} />

Adding Redirects programmatically to React Router

I'm trying to add a bunch of redirects given an array of old routes and new routes so I came out with this component:
const redirectUrls = [
{ oldUrl: '/robin', newUrl: '/users' },
{ oldUrl: '/batman', newUrl: '/courses' }
];
export default Redirects = () => (
redirectUrls.map((url, index) => <Route key={index} exact path={url.oldUrl} render={() => <Redirect to={url.newUrl} />} />)
);
Which works fine, but I wanted it to be simplier so I removed the Route and left only the redirect like this:
export default Redirects = () => (
redirectUrls.map((url, index) => <Redirect key={index} exact from={url.oldUrl} to={url.newUrl} />))
But it won't work, all the redirects take me to the last route, which in this case is /courses, and its weird because if I do this:
<Switch>
...
<Route path='/users' exact component={users} />
<Route path="/courses" exact component={CoursesList} />
<Redirect from='/robin' to='/users' />
<Redirect from='/batman' to='/courses' /> // having them like this works fine
</Switch>
So it makes no sense for them fail when I create them with a map and I haven't found anything that leads to the cause nor to a solution.
You need to wrap the exported redirects in a switch:
const Redirects = () => {
return (
<Switch>
{redirectUrls.map(url => (
<Redirect from={url.oldUrl} to={url.newUrl} />
))}
</Switch>
);
};
export default Redirects;
That's only if you actually need to make a component out of them. It's not totally clear what you need and are looking for since export default Redirects = () => is invalid syntax. If you just want to bundle them as some variable you can do:
export const Redirects = redirectUrls.map(url => <Redirect from={url.oldUrl} to {url.newUrl} />);
// App.js
<Switch>
<Route path='/users' exact component={users} />
<Route path="/courses" exact component={CoursesList} />
...
{Redirects}
</Switch>
Did you try this with exact props
<Switch>
...
<Route path='/users' exact component={users} />
<Route path="/courses" exact component={CoursesList} />
<Redirect exact from='/robin' to='/users' />
<Redirect exact from='/batman' to='/courses' /> // having them like this works fine
</Switch>
Reference https://github.com/ReactTraining/react-router/issues/4837

Injecting routes programmatically into a JSX router switch statement

I've been trying to inject some JSX routes into a router switch statement without success.
Basically I'm trying to be able to reuse the method commonRoutes for different scenarios so I do not have to repeat myself...
However when I inject the routes as illustrated the routing does not behave as expected and multiple routes will trigger at the same time instead of conditionally...
hopefully the code illustrates clearly what I'm trying to do:
First try:
class App extends Component {
commonRoutes() {
return (
<Switch>
<Route path="/route1" component={Component1} />,
<Route path="/route2" component={Component2} />,
<Route path="/route3" component={Component3} />,
</Switch>
);
}
app() {
return (
<React.Fragment>
<Header />
<div className="app-content">
<Switch>
<Redirect exact from="/" to="/folder" />,
{this.commonRoutes()},
<Route path="*" component={NotFound} />
</Switch>
</div>
<Footer />
</React.Fragment>
);
}
render() {
let content = '';
if (this.props.component === ComponentList.COMPONENT_APP) {
return this.appFrame(this.app());
}
if(this.props.component === ComponentList.COMPONENT_FOLDER) {
return this.appFrame(this.folder());
}
if (this.props.component === ComponentList.COMPONENT_EVENT) {
return this.appFrame(this.event());
}
return content;
}
appFrame(content) {
return (
<React.Fragment>
<CssBaseline/>
<NotSupported support={[{ name: 'ie', minSupport: 11 }]}/>
<Favicon url={`${AppConfig.CONTEXT}favicon.ico`}/>
<MuiThemeProvider theme={theme}>
{content}
</MuiThemeProvider>
</React.Fragment>
);
}
//... code
}
Second try:
class App extends Component {
commonRoutes() {
return [
<Route path="/route1" component={Component1} />,
<Route path="/route2" component={Component2} />,
<Route path="/route3" component={Component3} />
];
}
app() {
return (
<React.Fragment>
<Header />
<div className="app-content">
<Switch>
<Redirect exact from="/" to="/folder" />,
{this.commonRoutes()},
<Route path="*" component={NotFound} />
</Switch>
</div>
<Footer />
</React.Fragment>
);
}
}
Another way that comes to mind is using an object with keys to store the JSX routes and looping with map, but several attempts did not do the trick either.
I appreciate any help or direction.
First thing,
let content = ''
if (...) {
return this.appFrame(this.app());
}
...
return content
The preceding code works but not the way you expect. You're trying to return the content after the condition is matched. This just return the this.appFrame(...).
let content = ''
if (...) {
content = this.appFrame(this.app());
}
...
return content
Now, this works the way you're expecting. It assigns the value to the content and finally return the content.
Now, to your issue, you should be using exact props to return only the required component:
commonRoutes() {
return (
[
<Route exact path="/route1" component={Component1} />,
<Route exact path="/route2" component={Component2} />,
<Route exact path="/route3" component={Component3} />
]
);
}
Also, ensure to use unique key when you render array of elements. In your case, it is [<Route key={'unique-key'} />,...].
And also remove path from here:
<Route path="*" component={NotFound} />
{/* -----^^ not required react router 4 */}

Routes inside component previously routed

I am using react-router-dom 4.2. I have my App.js with Authenticated components inside. This components are created by me and add a little of business logic, create the component via React.createElement, and route them via Route component. Nothing unusual.
The App.js:
// ...
const App = props => (
<BrowserRouter>
<Fragment>
<Switch location={location}>
<Route
exact
path={URLS.ROOT}
render={() => <Redirect to={URLS.DASHBOARD} />}
/>
<Authenticated
{...props}
resource={ResourcesCode.DASHBOARD}
patent={PatentsCode.VIEW}
path={URLS.DASHBOARD}
component={Dashboard}
/>
<Authenticated
{...props}
resource={ResourcesCode.SUBSCRIBE}
patent={PatentsCode.VIEW}
path={URLS.SUBSCRIBE}
component={Subscribe}
/>
</Fragment>
</BrowserRouter>
// ...
Inside of the component Subscribe (mentioned above in the 2nd Authenticated component), I have more routes as you can see below:
// ...
<Route
path={URLS.SUBSCRIBE}
exact
render={() => (
//...
)}
/>
<Route
path={URLS.SUBSCRIBETWO}
exact
render={() => (
//...
)}
/>
// ...
The point is that this routes on the child component (Subscribe) are ignored.
Why are them ignored? How can I solve it?
I really need this routes inside the child component. I don't want to move them to App.js
IMPORTANT EDIT:
The second route is ignored, I realized that the first doesn't. In other words, The Route component with path={URLS.SUBSCRIBE} is working, but the component with path={URLS.SUBSCRIBETWO} is ignored, so here is the problem to solve.
EDIT:
For if you need, the Authenticated component:
// ...
}) => (
<Route
path={path}
exact={exact}
render={route => {
if (!authenticated) {
if (loggingIn) {
return '';
}
return <Redirect to={URLS.LOGIN} />;
}
if (!roleSubReady) {
return '';
}
if (path !== URLS.SUBSCRIBE && user.pendingSubscription) {
if (isLoading) {
return '';
}
return <Redirect to={URLS.SUBSCRIBE} />;
}
if (path === URLS.SUBSCRIBE && !user.pendingSubscription) {
if (isLoading) {
return '';
}
return <Redirect to={URLS.DASHBOARD} />;
}
if (resource && !checkPermission(user, resource, patent)) {
return <NotAuthorized history={route.history} />;
}
return (
<React.Fragment>
<Menu user={user} path={path} isLoading={isLoading} />
<Header show={showHeaderAndFooter} user={user} path={path} />
<MainContent>
{React.createElement(component, {
user,
resource,
...route,
})}
<Footer show={showHeaderAndFooter} />
</MainContent>
</React.Fragment>
);
}}/>
);

Categories

Resources