I am trying to use reactjs
and react-router
(1.x
) with my Django application but I am having a hard time putting all this together. Here is the github project just incase I dont provide enough information within this question.
I created a path="about"
within my routes.js
var routes = (
<Router>
<Route path="/" ponent={ Views.Layout }>
<IndexRoute ponent={ Views.Index } />
<Route path="about" ponent={ Views.About } />
</Route>
<Route path="*" ponent={ Views.RouteNotFound } />
</Router>
);
export default routes;
My layout.js
class Layout extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div id="review-web">
<header className="header">
<LogoElement />
<CenterPiece />
</header>
<div>
{ React.cloneElement(this.props.children, { path: this.props.path }) }
</div>
<Footer />
</div>
);
}
}
export default Layout;
When I enter in localhost.8000/about
I get a 404
Django error
My goal is to keep the frontend and backend separate so I believe I should be able to use Django as just an endpoint for data and not for rendering views.
I am trying to use reactjs
and react-router
(1.x
) with my Django application but I am having a hard time putting all this together. Here is the github project just incase I dont provide enough information within this question.
https://github./liondancer/django-cherngloong
I created a path="about"
within my routes.js
var routes = (
<Router>
<Route path="/" ponent={ Views.Layout }>
<IndexRoute ponent={ Views.Index } />
<Route path="about" ponent={ Views.About } />
</Route>
<Route path="*" ponent={ Views.RouteNotFound } />
</Router>
);
export default routes;
My layout.js
class Layout extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div id="review-web">
<header className="header">
<LogoElement />
<CenterPiece />
</header>
<div>
{ React.cloneElement(this.props.children, { path: this.props.path }) }
</div>
<Footer />
</div>
);
}
}
export default Layout;
When I enter in localhost.8000/about
I get a 404
Django error
My goal is to keep the frontend and backend separate so I believe I should be able to use Django as just an endpoint for data and not for rendering views.
Share Improve this question asked Oct 19, 2015 at 18:33 LiondancerLiondancer 16.5k54 gold badges163 silver badges262 bronze badges 5- when you go to "/" does it successfully serve the Views.Layout page? To me it looks like your application does not know to server or look at routes.js. Did you configure your app to use routes.js? – SilentDev Commented Oct 19, 2015 at 20:28
-
@user2719875 Right now my application uses this to use
route.js
. If I were to enterlocalhost:8000/
it will display this ponent] – Liondancer Commented Oct 19, 2015 at 21:21 - does it work if you do: <Route path="/about" ponent={ Views.About } /> (see the slash I used at the beginning of the path). Edit: Also, are you sure you don't want to include this line "<Route path="about" ponent={ Views.About } />" on it's own? It's currently nested inside the other route. – SilentDev Commented Oct 19, 2015 at 21:24
-
1
You'll need to split your route handling in the Django app - e.g. serve anything prefixed by
/api/*
with Django directly, and anything else (wildcard) to/path/to/your/index.html
- which is your React app. Otherwise Django interprets the/about
route as it's own - it doesn't talk to the React app whatsoever (it can't). – elithrar Commented Oct 20, 2015 at 3:03 - @elithrar nice idea! but in case of wildcard * server will return http status_code 200 for every request, but it's nice to return http status_code 404 for non existed urls. – ramusus Commented Mar 22, 2016 at 10:55
5 Answers
Reset to default 8I faced with the same issue and ended up with this solution.
settings.py:
REACT_ROUTES = [
'login',
'signup',
'password-reset',
'password-change',
'about',
...
]
urls.py:
routes = getattr(settings, 'REACT_ROUTES', [])
urlpatterns = [
...
url(r'^(%s)?$' % '|'.join(routes), TemplateView.as_view(template_name='index.html')),
]
I don't like to duplicate all react-routes in django settings, but if we put everything there url(r'^.*$')
, server will always return HTTP status_code 200. And this is only one way to be able return valid HTTP status_code 404 for non existed urls.
I was inspired by ramusus' answer. I'm using the (I think) newer django.urls.re_path
. I'm a bit skeptic about this ment and if it would be better or worse if the 404 was handled by the frontend. This is how I implemented it:
frontend/views.py
from django.shortcuts import render
def index(request):
return render(request, 'frontend/index.html')
frontend/urls.py
from django.urls import re_path
# Catch all pattern
urlpatterns = [
re_path('.*/', views.index, name='index'),
]
main/urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework.authtoken import views
urlpatterns = [
path('admin/', admin.site.urls),
...,
path('api-auth/', include('rest_framework.urls')),
path('', include('some_apps.urls')),
...,
# Put this at the end! This way, Django tries all
# its API URLs and if it doesn't find anything it
# redirects to the frontend
path('', include('frontend.urls'))
]
react front-end
// stuff ...
const Page404 = () => {
return (
<h3>404 - Not found</h3>
);
};
class App extends Component {
render(){
return (
<Router>
<Navbar />
<Switch>
// React handles any paths you specify, e.g. within the switch
<Route exact path='/some_paths/' ponent={SomeComponents} />
// If nothing matches...
<Route ponent={Page404} />
</Switch>
</Router>
)
}
}
// stuff...
My app serves the same client JS for all valid routes. Please excuse the Flask code.
@blueprint.route('/stuff/<path:path>', methods=["get"])
@blueprint.route('/', methods=["get"])
def index(path=None):
return render_template('app.html')
I could resolve this by using HashRouter
in the React app. This adds a #
to the beginning of the url and you can use an empty path in the Django urls.py
(your path would look like this: example./#/about/
)
Here is a good explanation (Don't forget to upvote).
Your files would look like this:
App.tsx
<Router>
<Switch>
<Route path="/article/:articleID">
<Article />
</Route>
{/* your routes */}
</Switch>
</Router>
And then simply an empty path. urls.py
urlpatterns = [
path("", TemplateView.as_view(template_name='index.html'))
]
Based on ramusus answer, this is how I've now fixed it.
As url doesn't work with Django 2 and up anymore. And ramuses answer also seems to be using Python 2, looking at the string formatting. This is using Python 3(.6).
(Although I am sure that there is a more elegant way of doing this, but it works and helps me get a step further in getting my project up and running.)
settings.py: (as ramusus suggested)
REACT_ROUTES = [
'login',
'signup',
'password-reset',
'password-change',
'about',
...
]
in main urls.py: (partly as ramusus suggested)
from django.conf import settings
react_routes = getattr(settings, 'REACT_ROUTES', [])
for route in react_routes:
urlpatterns += [
path('{}'.format(route), TemplateView.as_view(template_name='index.html'))
]