Building a SPA with react on top of MVC Routes
Asked Answered
P

3

6

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.

Pleurodynia answered 2/8, 2016 at 12:17 Comment(3)
you can try react.netPlausive
@Clément Péau did you find a solution?Zante
@Sag1v Sadly not.Address
Z
14

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

Zante answered 20/3, 2017 at 15:58 Comment(1)
I just saw that I updated without thanking you. But your solution was working for me and greatly appreciated, so thank you very much :)Address
U
0

I fixed react routing in ASP.NET + React SPA solution (.NET 5.0) by adding exact path instead of path for react-router-dom.

Unbeknown answered 6/8, 2021 at 22:27 Comment(0)
P
0

A simple solution is using the basename property of BrowserRouter in App.sjx:

...
import {
    BrowserRouter,
    Switch,
    Route
} from "react-router-dom";
...

const App = () => {
    const siteName = window.location.pathname.split("/")[1];
    return (
<BrowserRouter basename={`/${siteName}/React`}>
  <div>
   <Header />
   <Switch>                       
    <Route path="/users">
     <Users />
    </Route>
    <Route path="/map">
      <MapPage />
    </Route>
    <Route path="/">
     <HomePage />
    </Route>
   </Switch>
   <Footer />
   </div>
</BrowserRouter>
 );
}
export default App;
Popularity answered 16/11, 2021 at 10:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.