I have an API that has routes managed by MVC.
On top of that i want to build a SPA with react.
However the routes I build from inside my react app cannot be reached, i get an 404 from ISS, here us a stub from my code.
export default class Layout extends React.Component { render() { <div> <Router history={ hashHistory }> <Route path="/" component={ Home } > <Route path="login" component={ Login } /> </Route> </Router> <div> }
When I execute this code as a standalone whithout the backend, it works flawlessly.
Is there a way to tell MVC to render reacts routes for a set url, let’s say “/app/*”.
Thanks in advance.
Advertisement
Answer
As i mentioned in my comment, i may have a solution that can fit your needs.
This solution requires an MVC
Controller
and a relevant MapRoute()
.
The general idea is to deliver the index.html
page via MVC
using a controller
and cshtml
and configure on react-router
a basename
when creating browserHistory
.
The key here is that the basename
value must contain the entire path (without the domain) up to the controller
name.
for example:
given this controller
:
public class ReactController : Controller { public ActionResult Index() { return View(); } }
and cshtml
:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta charset="utf-8" /> <title>app name</title> <link href="path/to/file.css/if/needed" rel="stylesheet" /> </head> <body> <div id="app"></div> <script src="path/to/bundle.js"></script> </body> </html>
and routeMap
:
routes.MapRoute( name: "reactApp", url: "react/{*pathInfo}", defaults: new { controller = "React", action = "Index", id = UrlParameter.Optional } );
Now, lets say your app is published under http://example.org/appName/
then you’ll need to make sure react-router won’t delete the "appName"
portion of the URL when changing it.
for example, if you’re in the Home Page – http://example.org/appName/home
and you move to the About Page, you want react-router
to keep the "appName"
like so: http://example.org/appName/react/about
and not like so http://example.org/about
.
Although this will work just fine as you’re not posting this URL back to the server, you will face a problem when you will try to go directly to the “About” page. the server will return a 404 when you send the request with this URL: http://example.org/about/
instead of this one: http://example.org/appName/react/about
.
My soulution to this problem is to pass react-router
a basename
that includes the appName
+ sub folders (if any) + the controller name.
I’m using useRouterHistory
and creating the browserHistory
instead of import
it from react-router
const browserHistory = useRouterHistory(createHistory)({ basename: appName });
the appName
variable is as follow:
const controller = "/react"; const pathName = window.location.pathname; const appName = pathName.substring(0,pathName.indexOf(controller) + controller.length);
This can be refactored as a function but basically it gets the pathname
up to the controller name (as a convention with your MVC app) including the controller name.
that way react-router
will keep this path on every URL change.
In our case "appName/react"
.