Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 486
Clément Péau Avatar asked Aug 02 '16 12:08

Clément Péau


People also ask

Can you use react with MVC?

ReactJS.NET makes it easier to use Facebook's React and JSX from C# and other . NET languages, focusing specifically on ASP.NET MVC (although it also works in other environments). It supports both ASP.NET 4 (with MVC 4 or 5), and ASP.NET Core MVC. It is cross-platform and can run on Linux via Mono or .

What is a good place to register routes in an MVC application?

Every MVC application must configure (register) at least one route configured by the MVC framework by default. You can register a route in RouteConfig class, which is in RouteConfig. cs under App_Start folder.

Can we use react for single page application?

React is great for single page applications because it allows developers to create applications that are mobile first and responsive. React allows developers to create applications that are fast and easy to update, which is great for mobile applications.


1 Answers

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

like image 98
Sagiv b.g Avatar answered Oct 03 '22 21:10

Sagiv b.g