Reputation: 323
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.
Upvotes: 6
Views: 10214
Reputation: 953
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;
Upvotes: 0
Reputation: 197
I fixed react routing in ASP.NET + React SPA solution (.NET 5.0) by adding exact path
instead of path
for react-router-dom.
Upvotes: 0
Reputation: 31024
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"
.
Upvotes: 14