Skip to content
Advertisement

Building a SPA with react on top of MVC Routes

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 Pagehttp://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".

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement