Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

404 page not found using Django + react-router

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.com/liondancer/django-cherngloong

I created a path="about" within my routes.js

var routes = (
    <Router>
        <Route path="/" component={ Views.Layout }>
            <IndexRoute component={ Views.Index } />
            <Route path="about" component={ Views.About } />
        </Route>
        <Route path="*" component={ 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

enter image description here

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.

like image 342
Liondancer Avatar asked Oct 19 '15 18:10

Liondancer


4 Answers

I 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.

like image 129
ramusus Avatar answered Oct 31 '22 12:10

ramusus


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')
like image 30
Jesvin Jose Avatar answered Oct 31 '22 11:10

Jesvin Jose


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.com/#/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'))
]
like image 25
Myzel394 Avatar answered Oct 31 '22 11:10

Myzel394


I was inspired by ramusus' answer. I'm using the (I think) newer django.urls.re_path. I'm a bit skeptic about this comment 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/' component={SomeComponents} />
                    // If nothing matches...
                    <Route component={Page404} />
                </Switch>
            </Router>
        )
    }
}

// stuff...
like image 34
Kostas Mouratidis Avatar answered Oct 31 '22 11:10

Kostas Mouratidis