I have a React app I'm playing with and using with a star wars API I built locally.
The first two routes work just fine but I don't understand why the third one doesn't work.
My guess is that going to the third route the second component thinks that the work "edit" is the parameter.
Question is, how can I make the third route work as I would like or do I have to take another approach.
I was hoping to have the Edit Episode page be in the same group as the components I use in the "starwars" path.
<Route path="/starwars" exact component={Movies} />
<Route path="/starwars/:id" component={Episode} />
<Route path="/starwars/edit/:id" component={EditEpisode} />
Try adding exact attribute to the second route. It should solve the problem.
<Route path="/starwars" exact component={Movies} />
<Route path="/starwars/:id" exact component={Episode} />
<Route path="/starwars/edit/:id" component={EditEpisode} />
Without exact attribute, all the incoming request to /starwars/{whatever-after-this} matches to the second route and it stops there.
Can you please change the order of the Route and set exact keyword to the /starwars/edit/:id path.
<Route path="/starwars" exact component={Movies} />
<Route exact path="/starwars/edit/:id" component={EditEpisode} />
<Route path="/starwars/:id" component={Episode} />
Hope this will work for you!
Can you check thepublicPath on the output property in your webpack.config file. This should point to the root of your app.
I've been there and this worked for me.
output: {
path: path.resolve('dist'),
publicPath: '/'
}
Related
I know this issue has to do with a fundamental misunderstanding of how React Router works, and more specifically, probably the history object. I have a component called Search, which lets the user search for a particular city. This component appears in multiple places throughout the app, including '/' and '/:cityname'.
From '/', the component works as expected, and correctly pushes the new url param onto the url and the url becomes '/vancouver'. However, from '/vancouver', when I use this same component, the url does not behave as expected. For instance if I enter Istanbul, I am correctly directed to /istanbul, but then as I proceed through the app and click on items, I expect to be directed to '/istanbul/item1'. However, what happens currently is that I end up at '/istanbul/istanbul/item1', which of course is not found, and returns a 404.
Here is the function that gets called when a city is selected (found within Search component)
const onSuggestionSelected = (event, { suggestion }) => {
props.history.push(`/${suggestion.nickname}`)
}
App.js with routes
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/terms-of-service" component={TermsOfServicePage} />
<Route exact path="/privacy-policy" component={PrivacyPolicyPage} />
<Route exact path="/:cityname/personalize" component={FilterPage} />
<Route exact path="/:cityname/experiences" component={SearchPage}>
<Redirect to="/:cityname" />
</Route>
<Route exact path="/:cityname" component={SearchPage} />
<Route exact path="/:cityname/experiences/:experiencename" component={ExperiencePage} />
<Route exact path="/:cityname/experiences/:experiencename/summary" component={(routeProps) => <SummaryPage {...routeProps} />} />
<Route exact path="/:cityname/experiences/:experiencename/payment" component={PaymentPage} />
<Route exact path="/:cityname/experiences/:experiencename/payment-successful" component={PaymentSuccessfulPage} />
<Route component={NotFoundPage} />
<GlobalStyle />
</Switch>
ExploreMore Button
<ButtonWrapper onClick={sendAnalyticsData}>
<LetsGoButton to={{
pathname: `${props.match.params.cityname}/experiences/${experience.nickname}`,
state: props.location.state
}}
palette="tertiary">
Explore more
</LetsGoButton>
</ButtonWrapper>
Please let me know if there is anything else that I can provide that would be helpful. I've tried to do research on how history.push works exactly, but I haven't been able to find much. My best guess is that it takes the current location, and adds on the provided url. Even if that's the case, I can't understand why it would be applying istanbul twice.
I figured out the problem on this one. One of the commenters suggested that I had been using relative paths rather than absolute. I erroneously thought that he was incorrect, seeing as I seemingly have the full url in there. My mistake was to not start off the url with /
before:
${props.match.params.cityname}/experiences/${experience.nickname}
after:
/${props.match.params.cityname}/experiences/${experience.nickname}
I hope this helps someone out.
what I want to do is that my website has admin panel with the following routes /admin/.... and then the normal web would be /...
But the urls come together when I enter / works well but when I enter /admin you see the web menu and the admin menu when you would only have to see the menu of the administrator I leave the demo that performed in CodeSandBox, I hope you can help me.
https://codesandbox.io/s/react-router-admin-users-5wzte
Greetings and thanks.
Wrap your routes in a Switch component. The Switch will return only the first matched route. More info is available here:
https://reacttraining.com/react-router/web/guides/basic-components
The issue is because, your path /admin getting matched with your both Route.
You need to provide an exact prop,
<Route
path="/"
exact //exact prop will help to match exact path
render={userProps => (
<Layout match={userProps.match}>
<h2>Menu Web</h2>
<Route exact path="/" component={Home} /> //Add exact here also otherwise it will get match for path `/contact`
<Route path="/contact" component={Contact} />
</Layout>
)}
/>
Also you need to make use of Switch, which
Renders the first child <Route> or <Redirect> that matches the location.
Just wrap your Route with Switch.
Here is my Router Implementation
<BrowserRouter>
<div>
<Route exact path="/" component={ProfilesIndex} />
<Route exact path="/profiles" component={ProfilesIndex} />
<Route exact path="/profiles/new" component={ProfileEditor} />
<Route exact path="/profiles/:id" component={ProfileEditor} />
</div>
</BrowserRouter>
When I am browsing to /profiles/new path, it is rendering the ProfileEditor component twice. For every other route, it is working fine.
Can someone suggest how to fix this problem ?
I found the answer after browsing into multiple sections in Router Docs. Problem was it was matching multiple routes
When user opens /profiles/new it matches two routes
/routes/new
/routes/:id
Because :id is like a wildcard * and it also matches new word so both routes get matched and hence the component gets rendered twice.
The solution is to wrap the routes with Switch if you do not want to match multiple routes.
<BrowserRouter>
<Switch>
<Route exact path="/" component={ProfilesIndex} />
<Route exact path="/profiles" component={ProfilesIndex} />
<Route exact path="/profiles/new" component={ProfileEditor} />
<Route exact path="/profiles/:id" component={ProfileEditor} />
</Switch>
</BrowserRouter>
For anyone coming here from v6+
exact prop no longer exists, the paths are exact by default if they aren't appended a wildcard *
However I was still getting a double render. I ran a prod build and checked and the double render is gone so probably nothing to worry about - sometimes hooks run twice in development mode (I guess that's what's happening internally)
for me, this is because of React.StrictNode which is wrapped arround App component.
it intentionally double render components (only in development) to enforce you, not use side effects on some of your component's
lifecycle events.
the reason behind that is documented here
I have a route
<Route exact path="/view/:personID" component={PersonView} />
It works fine, however /view still renders, albeit with no person in it. Is there a way to disallow this path or turn in into a 404?
Answer was to use switch
<Switch>
<Route exact path="/view/:personID" component={PersonView} />
<Redirect from='/view' to='/' />
</Switch>
You can manage this on your component, in the render section test if you have your personID if not return a custom error/view.
Following the examples provided here https://reacttraining.com/react-router/examples/url-params.
I constructed my own route for my website like so:
<Router>
<div>
<Route path='/' exact component={Layout} />
<PublicRoute authed={this.state.authed} exact path='/login' component={Login} />
<PublicRoute authed={this.state.authed} exact path='/register' component={Register} />
<PrivateRoute authed={this.state.authed} path='/dashboard' component={Dashboard} />
<Route path='/cachaca/:bottle' component={Layout} />
<Route render={() => <h3>No Match</h3>} />
</div>
</Router>
That is pretty similar to the example given except for the fact that the navigation (or link to) is somewhere else in the page.
The route itself is working perfectly. I can get match information, i can sucessfully check whether a user is logged in or not and so forth.
My only problem is that the URL bar isn't changing to reflect the navigation changes, so if I am sitting at localhost:3000/cachaca/1234 and click to go home, the home page will load but the URL bar will still show 'localhost:3000/cachaca/1234'.
I've seen similar posts to mine from react router 2/3 that seem to indicate that the history prop is what's causing this issue - but I don't believe that to be the case in Router 4.
In addition to that, the example in the react training website works and mine (which seems to be following the same steps) does not.
Am I missing something here? Why am I not getting the same results as in the training website.
Here is the navigation link I am using:
<Link to={"/"}>Home</Link>
Appreciate any help,
Thanks!
Wow, this is silly - but I wasted my entire day in this so will post this in the hope of saving someone else some time:
Turns out it wasn't working because I was doing my testing on the webpack-dev-server/ folder and react-router 4 seems to have a problem with that.
As soon as I went from http://localhost:3000/webpack-dev-server/cachaca/asdf to http://localhost:3000/cachaca/asdf the website started behaving as it should - both in content and its location in the URL bar.
Happy coding to all!