Can I use react router in django project? - javascript

I have a project that uses React in frontend and Django as backend.
Also I use react router in my project and the code looks like this:
<BrowserRouter>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/teachers" exact component={Teachers} />
<Route path="/courses" exact component={Courses}/>
<Route path="/about" exact component={About} />
<Route path="/posts" exact component={Posts} />
</Switch>
</BrowserRouter>
In django my urls file looks like this:
urlpatterns = [
path('', views.index, name="index"),
]
The problem is that whenever I try to navigate to the page from react router I get 404 error from django.

Dude I am having the same problem. From I have researched the answer is actually to throw a catch all at the end of your urls in django. I can only find the old way of doing it.
url(r'^(%s)?$' % '|'.join(routes), TemplateView.as_view(template_name='index.html'))
I am not sure how to do it with path but I had found it earlier. It might be
re_path(r'.*', views.index)
Just let me know if that works so I can go home and use it :)

Related

What exactly is <switch> used for in React Router?

I am new to React learning , and was trying to build an app using react-router-dom. I was able to implement basic routing when I came across the term 'switch'. Can anyone please explain me with a use-case example where we use switch and what is its use?
Since you are new am going to take a bit more time to explain with examples and also add some few things about it you may want to have handy.
So like Iddler said, Switch is more or less like the "Switch case" condition in any other languages but usually ends with the first match it finds.
<Switch>
<Route path="/home" component={Home} />
<Route path="/about" component="{About} />
</Switch>
That is an example of its most basic use. Switch determines the start and end of the block or condition. Each Route checks for the current path. supposing we were working on "www.test.com". All of "www.test.com" is the root "/". So the Route checks for the path after the root. so if you had "www.test.com/home", "/home" comes after the root so the "Home" component will be loaded in our example above and if you had "www.test.com/about" the "About" component is loaded.
Be mindful that you can use any names. the components and paths do not need to be the same.
There are also cases when you might want to use exact to match an exact path. this is useful when you have similar paths. eg "/shop" and "/shop/shoes". using exact ensures Switch matches exact paths and not just the first.
Eg:
<Switch>
<Route exact path="/shop" component={Shop} />
<Route exact path="shop/shoes" component="{Shoes} />
</Switch>
You can also use <Route... /> without the <Switch>.
Eg:
<Route path="/home" component={Home} />
so unlike direct component loads where you just load a component like <Home /> Routers work with the URLs.
Lastly, the <Route... /> path can take arrays of url to load same component.
Eg:
<Switch>
<Route path={[ "/home", "/dashboard", "/house", /start" ]} component={Home} />
<Route exact path={[ "/about", "/about/management", "/about/branches" ]} component="{About} />
</Switch>
I hope this helps. Let me know if you need clarifications of any sort. :)
UPDATE:
You are not required to write Routers in this same format always. below is another format you could use;
<Router>
<Switch>
<Route path="/home">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
</Switch>
</Router>
There are instances like am in now where you want to be able to handle what shows when a wrong URL is entered. like a 404page. you could use Router without a path. so like a regular switch statement, that becomes your default.
<Switch>
<Route path="/home" component={Home} />
<Route path="/about" component="{About} />
<Route component="{PageNotFound} />
</Switch>
Switch looks through Route's children and renders the first one that matches the current path, once it does it will not look for any other matches.
The Switch component will work much in the same way as the Router component, meaning we will still have nested Route components that need exact paths, etc.
The added functionality of Switch is that it will only render the first matched child. This is really handy when we have nested routes such as the below:
<Switch>
<Route path="/accounts/new" component={AddForm} />
<Route path={`/accounts/:accountId`} component={Profile} />
</Switch>
Say we put the above code in a component — we would see that both {AddForm} and {Profile} would render, since “/accounts/new” could look like either Route to a Router component. Router components render inclusively of all route matches. The Switch component will render exact matches, and only the exact match. This makes it ideal for these nested scenarios.

Serve another(standalone) page or static file in website built with react

I have a website built with react, which uses react-router. For some route I want to serve another page or static file, but since all request are forwarded to react router, its doesn't work.
for example
www.myapp.com/sitemap.xml
www.myapp.com/something.html
^ these link works first time, but once i load website then it doesn't work, as all request goe through react router.
Any solution to make it work all the time. Thanks.
Edit
I'm using apache server which is configured to redirect all request to index.html, i guess this is the reason for this behaviour. This is my configuration, but i don't know how to fix this.
Options -MultiViews
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]
Update
I tried solution suggested in answer.
my routes looks like this, for something.html i am loading ServerLoad component
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/about" component={About} />
<Route path="something.html" component={ServerLoad} />
<Route component={NoMatch} />
</Switch>
In ServerLoad component's componentDidMount function I did this. But it doesn't work.
componentDidMount() {
window.location.reload(true);
}
More
I have setup this project using create-react-app, and serving it by express server(like this). I'am not sure if i need to do some setting there to server other static files.
This should work:
const reload = () => window.location.reload();
<Router>
// all your routes..
...
// Your special routes..
<Route path="/sitemap.xml" onEnter={reload} />
<Route path="/something.html" onEnter={reload} />
</Router>
So, I think this should be pretty clear what it does ;)
Update:
if this is an option you can simply put target="_blank" attribute in your <Link>
IMHO this is from the UX perspective even better, because if these routes are not part of your main application, the user can just switch the Tab after visiting that special pages.
How about simply put your statics files like sitemap.xml inside React's public folder along side index.html.
I thinks this is the easiest way.
It's an unwanted behaviour of ServiceWorker.js use the comment below and change it in index.js of your React project (if you don't need a service worker) and it should work
import { unregister } from './registerServiceWorker';
unregister();
https://github.com/facebookincubator/create-react-app/issues/2715
If you still need a service worker and you want to avoid it having this behavior, consider installing a custom service worker, there you can establish a whitelist of paths to be ignored. For more information you can check the next link.
https://medium.com/swlh/how-to-implement-custom-service-worker-in-create-react-app-without-eject-bfa2c5f4ae96
Use Switch combined with a NoMatch component, combined with webdeb's solution:
<Router>
<div>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/admin" component={Admin} />
<Route component={NoMatch} />
<Route onEnter={() => window.location.reload()} />
</Switch>
</div>
</Router>
This will match routes, show 404 if no valid href exists, and show a file or something if it's a valid href.
If you need /terms to redirect to /terms.html, the code below worked for me with react-router 3.x.
const reload = () => window.location.reload();
<Router>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/terms.html" render={reload} />
<Route path="/privacy.html" render={reload} />
<Route path="/terms" render={() => <Redirect
to={{
pathname: "/terms.html"
}}
/>}
/>
<Route path="/privacy" render={() => <Redirect
to={{
pathname: "/privacy.html"
}}
/>}
/>
</Switch>
</Router>
1. Create folders for each HTML file inside the public folder.
2. Add route paths (path= name_of_folder_contained_static_file)
3. Call route paths as you want :)
Demo:
If the pages are unrelated to the Reactjs App at all(i.e. using another directory), I think we can route it from Node layer using the following code, so that the structure is more intuitive:
app.use('/url_to_static_pages', express.static('path_to_static_files'));

Default Route With React Router 4

fI currently have the following routes defined in my application:
/
/selectSteps
/steps
/steps/alpha
/steps/beta
/steps/charlie
Which could also be visualised like this:
- (home)
- selectSteps
- steps
- alpha
- beta
- charlie
My root component looks like this:
<Route path="/" exact component={Home} />
<Route path="/select-steps" render={() => <StepSelectorContainer />} />
<Route path="/steps" component={StepsContainer} />
My Steps component does this:
steps.map(step => (
<Route
path={fullPathForStep(step.uid)}
key={shortid.generate()}
render={() => <StepContainer step={step} />}
/>
This all works nicely, but I don't want steps to exist as route in its own right. Only its child routes should be visitable. So I'm looking to lose the /steps route to leave my routes as:
/
/selectSteps
/steps/alpha
/steps/beta
/steps/charlie
How should I configure my routes for this? Ideally, hitting /steps would redirect to the first child route.
Actually, it's pretty straightforward...
Use Redirect component to... well, redirect.
<Redirect from="/steps" exact to="/steps/whatever" />
exact prop guarantees you won't be redirected from sub-route.
Edit: after all, Redirect does support exact (or strict) props. No need to wrap in Route. Answer updated to reflect that.
Pedr,
I think that this will solve your problem.
<Route path="/" exact component={Home} />
<Route path="/select-steps" render={() => <StepSelectorContainer />} />
<Route path="/steps" component={StepsComponent} />
And then in your StepsComponent render method, you can do this.
<Switch>
{steps.map(step => (
<Route
path={fullPathForStep(step.uid)}
key={shortid.generate()}
render={() => <StepContainer step={step} />}
/>}
<Redirect from="/steps" exact to="/steps/alpha" />
</Switch>
What this will do is render your steps component because it the route begins with /steps. After that is rendered, then it will render one of the nested routes based off the url. If the url is just "/steps", then it will redirect to the initial route listed here, in this case "/steps/alpa" by rendering the redirect. The Switch will make it so that it only renders one of the routes.
Credit to Andreyco for the redirect code.
I hope this helps.

react router NoMatch route on dynamic routing

I have this structure
<Route path="user" component={Users}>
<Route path=":userId" component={User}>
<Route path=":project" component={Project}/>
<Route path="*" component={NotFound} />
</Route>
<Route path="*" component={NotFound} />
</Route>
<Route path="*" component={NotFound} />
No matter how hard i try to set <NoMatch />, I always can get through url to either user id or project id that doesnt exist. This is boggling me for two days now and I'm so confused by different approaches / answers over the internet that I'm lost.
Using react-router v3.0.2
Edit: I was completely on the wrong track before. What I meant was, the fallback is for routes that are not defined, so something like /foo.
/user/55 and user/55/project are valid routes even if you don't have user no. 55 in your database - you can't use the fallback here.

React Router and route params

I've had a browse and I couldn't find anything solving this for me. I've got a problem with a routing requirement that I've got within my SPA. There is an optional parameter in the middle of a URL. For example, I would like both this:
/username/something/overview
and
/username/overview
To resolve to the same thing.
First Attempt
I first tried to use the parenthesis to mark this as an optional parameter.
<Route path='/:username(/:shard)' component={ProfileContainer}>
<IndexRoute component={OverviewContainer} />
<Route component={MatchHistoryContainer} path='/:username/(/:shard)/history' />
<Route component={DailyTrendsContainer} path='/:username/(/:shard)/trends' />
</Route>
However, the outcome of this is that username/history resolves to the root, because it thinks 'history' is the value of the shard routing parameter. So username/something/overview worked with this, but username/overview no longer worked.
Attempt 2
I took another run at it, by defining a whole new set of routes in the routing definition:
<Route path='/:username' component={ProfileContainer}>
<IndexRoute component={OverviewContainer} />
<Route component={MatchHistoryContainer} path='/:username/history' />
<Route component={DailyTrendsContainer} path='/:username/trends' />
<Route path='/:username/:shard' component={ProfileContainer}>
<IndexRoute component={OverviewContainer} />
<Route component={MatchHistoryContainer} path='/:username/:shard/history' />
<Route component={DailyTrendsContainer} path='/:username/:shard/trends' />
</Route>
</Route>
I put the history and overview routes above the ones with the optional parameters so that they would resolve first. I then declared the additional routes with the parameter (but this time not marked as optional) so it would resolve to those after it had tried the ones I wanted.
With this approach, history and overview worked a treat! However, the urls with the shard parameter in them no longer worked, and resulted in a loop, because whenever it tried to render out, it failed.
I was wondering if there is an idiom or someone with a little more experience of react router could point out something obvious I'm missing?
Yes we can put the optional params in the middle of the url, like this way:
<Route path='/test' component={Home}>
<Route path='/test(/:name)/a' component={Child}/>
</Route>
don't use the / after test it will be the optional params for Home.
In ur 1st case just remove the / after username, it should work, try this:
<Route path='/:username(/:shard)' component={ProfileContainer}>
<IndexRoute component={OverviewContainer} />
<Route component={MatchHistoryContainer} path='/:username(/:shard)/history' />
<Route component={DailyTrendsContainer} path='/:username(/:shard)/trends' />
</Route>

Categories

Resources