I've noticed a strange behavior in react-router.
I have my routes defined like so:
var routes = (
<Route name='app' path='/' handler={Master}>
<DefaultRoute handler={HomePage} />
{/* inject:route */}
<Route name='home' handler={HomePage} />
<Route name='issues' handler={IssuesPage} />
<Route name='security' handler={SecurityPage} />
<Route name='contactUs' handler={ContactUsPage} />
<Route name='docs' handler={DocsPage} />
{/* endinject */}
<Redirect from='/' to='/home' />
<NotFoundRoute handler={HomePage}/>
</Route>
);
Router.run(routes, function (Handler) {
React.render(<Handler />, document.body);
});
in our fork of https://github.com/shovon/generator-react-material-ui.
Clicking links in the LeftNav produces expected results.
Upon starting gulp, the redirect from / to /home works.
What seems weird and undesirable is when I type in something like http://localhost:3000/#/some-undefined-route.
As expected, the DefaultRoute handler takes over, and the home page content is visible. HOWEVER, the weird URL remains. What I would expect is for any undefined route to redirect to a pre-defined catch-all. For example, I want http://localhost:3000/#/some-undefined-route to automatically redirect to http://localhost:3000/#/home -- not just show that content.
We're trying to use a mixin with transitionTo() to achieve the desired effect, but I'm still wondering if anybody knows the "right" way to handle this. I also wonder if what I'm seeing is actually the intended react-router behavior. If I'm missing something, I'd love to be enlightened. Cheers!
Update
From taurose at react-router:
Have you tried
<Redirect from="*" to=".." />
when responding to https://github.com/rackt/react-router/issues/732.
What might help anybody else with a similar question is to be aware that you will have to provide a Redirect for each sub-route, as well.
Apparently, this set up is designed to allow more detailed route control and handling of things like 404s.
Initially, we suspected that might be the case, but I didn't understand how the splat ( from="*" ) works.
Maybe this will be useful to others.
Cheers.
Related
I have my app like that
<Router>
<div className="App">
<Link to="/" style={{ textDecoration: "none" }}>
<header>Project Issues</header>
</Link>
<Switch>
<Route exact path="/">
<Issues />
</Route>
</Switch>
</div>
</Router>
Inside Issues component, I choose to render one of two components based on a window width condition, one of the two components is called TwoPagesLayout, in this component when the user clicks on some text, it should go to another component called IssueDetails.
Here's the part of the TwoPagesLayout component:
{issues.map((issue: any) => (
<div>
<Link to="/Details" style={{ textDecoration: "none" }}>
<p className="issue-title">{issue.title}</p>
</Link>
<hr></hr>
<Switch>
<Route exact path="/Details">
<IssueDetails issue={issue} />
</Route>
</Switch>
</div>
))}
The problem is when I click on the text, it goes to that url "http://localhost:3000/Details" but it appears as a blank white page, it doesn't render what is inside the page.
Hope I have made it clear, I am new to react so I think the question maybe sounds common.
<Route exact path="/">
<Issues />
</Route>
Since you've marked this as exact, once the url changes to /Details, it no longer matches, and so Issues unmounts. Since Issues unmounts, so too does its descendant IssueDetails. You probably want to do:
<Route path="/">
<Issues />
</Route>
The Issues component will only render on the "/" path. When the page is showing "/Details" the Issues component will not render, and that includes the nested Router.
For this reason (they’re confusing), I personally try to avoid nested routers, so I would suggest keeping all the Route components together unless you have a reason otherwise!
I'm creating a simple react app. I need to load a component from a button click. When I click the edit button I need to load the edit component. I tried it using <Link>. But I can't understand how to give the relative path. It means it need to load it like http://localhost:3002/viewTicket/603c9a02a2ccd501f45f820e/edit. I need to load it from http://localhost:3002/viewTicket/603c9a02a2ccd501f45f820e. How can I give the relative path?
App.js
<Provider store={configureStore()}>
<BrowserRouter>
<div className="App">
<LayoutWrapper>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/viewTicket/:id" exact component={ViewTicket} />
<Route path="/viewTicket/:id/edit" exact component={EditTicket} />
</Switch>
</LayoutWrapper>
</div>
</BrowserRouter>
</Provider>
Ticket.js
<Link to="/viewTicket/:id/edit">
<Button size="lg" onClick={this.handleEdit}>
<Pencil />
Edit
</Button>
</Link>
But url lokks like this.
Is there any other way to do this?
You forgot to include the actual ID in the URL. You're just directing the user to this literal string that has ":id" in it:
<Link to="/viewTicket/:id/edit">
Whatever your ID values is (for demonstration let's assume it's in a variable called id), you'd use that to build your URL:
<Link to={`/viewTicket/${id}/edit`}>
As an aside, this is a very strange structure and will likely lead to confusion:
<Link to="/viewTicket/:id/edit">
<Button size="lg" onClick={this.handleEdit}>
Putting a button inside of a link means that you're trying to simultaneously do two different things. Should this.handleEdit be invoked? Or should the user be redirected by the link? It's best to invoke a single operation. If some logic needs to happen inside of this.handleEdit before redirecting the user, then remove the <Link> and manually redirect the user (likely using the useHistory hook) after performing that logic.
very new to react router. i know this code isn't written the cleanest but how come when i click the button (Link to='/question') it renders
and BUT also renders the button still. i tried
setting it into a new route but unfortunately still doesn't work.
also is this how you would structure a basic router that needs to
render two separate components? i see i can do render={} or component={}
but not really sure how to render more than one component with one
router---- wit those two questions considered i basically just want
this button to render a new page ('/question') that has two components on it--- AFIB and QFIB and nothing else (right now its rendering the button and the two new components in addition... here is the code:
<div class='qAndAContainer'>
<Router>
<Link to='/question'><button className="px-4 nextQuestion startButton py-2 bg-pink-600 text-white text-sm uppercase font-medium rounded hover:bg-pink-500 focus:outline-none" >Begin
</button>
</Link>
<Route path='/question' component={(props) => (
<QFIB {...props} />
)} />
<Route path='/question' component={(props) => (
<AFIB {...props} />
)} />
</Router>
</div>
)
}
export default StartTest
React Router's Route component is basically a glorified string-match for your browser's URL.
In this case, what you're presenting to React Router is three Routes with the same strings to match, so it shows them all!
This is actually useful, for example rendering the same navigation bar for /dashboard AND /dashboard/messages.
But in your case, you just want one route or the other. So for React Router to understand you just want one of many, you need to wrap your Routes with a Switch component. React Router will only render the first match it finds, from top to bottom. Try to order your Routes in a Switch from most specific (longest paths) to least to get the best results.
I don't really care for the render or children props of Route (although they have their purposes), I usually prefer composing just like normal components.
<Router>
<Switch>
// this will actually match /question123/asdf/kdkd?foo=bar as well...
<Route path="/question">
<QFIB />
<AFIB />
</Route>
// `exact` tells the Route is must be... exact
<Route path="/" exact>
<Link to="/question">Go to Questions</Link>
</Route>
</Switch>
</Router>
Recently I've tried building a web platform trough React. Everything's fine, everything's work ecc.
But I've run in many problems when I tried to create a different page for the user login:
I already had Routes in my code, so when I tried to add other Routes to another js file they simply didn't work.
I have no clue how to do the authentication in react router, I've tried in many ways, followed many tutorials but nothing worked out.
<Switch>
<Route exact path='/' component={Feed}/>
<Route path="/user" component={Profilo}/>
<Route path='/explore-page' component={ExplorePage} />
<Route path='/events-page' component={EventsPage} />
<Route path='/calendar-page' component={CalendarPage} />
<Route path='/stats-page' component={StatsPage} />
<Route path='/form' component={FormPage}/>
<Route path="/user" component={Profilo}/>
<Route path="/user/:userId" component={Profilo} />
</Switch>
This is all the routes I'm currently using inside a div to get the react component rendered.
As I said before adding other routes in an upper file wouldn't give me a response.
So, in the end, I'm gonna ask you where should I put the route for the login and the home? In there or I should just moving everything?
Thank you in advance.
One simple way is adding the logic to handle authentication in your render function.
If the user is not authenticated. Redirect to the login page. Otherwise, go to your component
render() {
if (!this.props.isAuth) {
return (
<Switch>
<Route exact path="/" component={Login} />
<Redirect to="/" />
</Switch>
);
}
return (<Switch>
<Route
// your router
/>
</Switch>);
}
I was trying different ways of declaring routes in a modular way. I came across to a strange behaviour:
<Switch>
<Route path='/1' component={Route1} />
<ModuleLikeRoutes />
<Route path='/2' component={Route2} />
</Switch>
React router completely ignores /2 and doesn't render Route2. I couldn't find any reason why.
I know I can import a 'module' component like
<Route path='/module' component={ModuleComponent} />
and probably it's the better way to do it. But I'm just curios how/why it ignores the routes after a custom component. Why I cant render Route2 in the example?
Here is a working fiddle https://jsfiddle.net/o4dtrpag/
A Switch will render only one of its children. If the path doesn't match /1 it will check the second one which is ModuleLikeRoutes, and that will be rendered every time, effectively making all components after it meaningless.
I am not sure if it is a bug or a not-supported feature by the library. However, the below code works by order the ModuleLikeRoutes to the last position.
<Switch>
<Route path='/1' component={Route1} />
<Route path='/2' component={Route2} />
<ModuleLikeRoutes />
</Switch>