![](/img/trans.png)
[英]Router context undefined with BrowserRouter in react-router-dom v5
[英]dynamic basename with BrowserRouter in react-router-dom
请我在构建多租户 SaaS 解决方案时遇到问题。 对于每个租户,我希望他们使用一个子域,这样我就可以从 url 获取子域,调用 REST api 返回有关该租户的数据。
例如,
tenant1
。tenant1.localhost:3000
。 我得到了网址,并得到了域名。 然后我与域进行调用以获取租户的主题(这存储在 localStorage 中)。 不幸的是,我们部署在我公司的 k8 上,所以我无法模仿这种行为。 因此,devOps 团队建议我在上下文中使用子域,从而拥有localhost:3000/tenant1
。 记住租户是动态的,所以我试过这个:
<BrowserRouter basename={"/:tenant"}>
<Switch>
<Route exact path="/login" name="Login" component={Login} />
<Route exact path="/set-password/:token" name="Set Password" component={SetPassword} />
<PrivateRoute path="/" name="Default Layout" component={DefaultLayout} />
</Switch>
</BrowserRouter>
然而,上面的解决方案使我的 url 为 localhost:3000/:tenant/login
请问我如何在路由器中使用动态基名,以便它可以接受:
localhost:3000/tenant1
localhost:3000/tenant3
localhost:3000/tenant2
等等。
它可以允许任何,我的应用程序处理输入的错误域
我终于使用了以下代码的动态租户
class App extends Component {
state = {
domain: ""
}
componentWillMount () {
const { domain } = this.state;
const parsedData = window.location.pathname.split("/");
let domain = parsedData[1];
this.setState({ domain: domain })
this.props.onGetTenant(domain);
}
render () {
const { domain } = this.state;
return () {
<BrowserRouter basename={"/"+domain}>
<Switch>
<Route exact path="/login" name="Login" component={Login} />
<Route exact path="/set-password/:token" name="Set Password" component={SetPassword} />
<PrivateRoute domain={domain} path="/" name="Default Layout" component={DefaultLayout} />
</Switch>
</BrowserRouter>
}
const mapStateToProps = state => {
const { tenant} = state;
return { tenant};
};
const mapDispatchToProps = (dispatch) => {
return {
onGetTenant: bindActionCreators( tenantActions.get, dispatch)
}
};
export default connect(mapStateToProps, mapDispatchToProps)(App)
这对我有用 react >16 和 react-router-dom v5
export const App = () => {
return (
<BrowserRouter>
<Switch>
<Route path="/:tenantId?" component={LayoutRoot} />
</Switch>
</BrowserRouter>
);
};
export const LayoutRoot = () => {
var { tenantId } = useParams();
//TODO: add some validation here and inform user if tenant is invalid
return (
<BrowserRouter basename={tenantId}>
<Switch>
<Route path="/login" component={LoginComponent} />
<Route path="/dashboard" component={DashboardComponent} />
</Switch>
</BrowserRouter>
);
};
这是我编写的代码沙盒和实用程序:
https://codesandbox.io/s/react-router-dom-dynamic-basename-xq9tj?file=/index.js
import urlJoin from 'url-join';
// it's important to have an identifier in their app
export const APP_ROOT_URL = '/my-app';
export const getBaseUrlPath = () => {
const currentPath = document.location.pathname || APP_ROOT_URL;
const startOfAppBase = currentPath.indexOf(APP_ROOT_URL);
let base = currentPath;
if (startOfAppBase !== -1) {
base = currentPath.substr(0, startOfAppBase);
}
base = urlJoin(base, APP_ROOT_URL);
return base;
};
您可以使用key
属性呈现对路由器basename
的更新。 对键值的任何更改都会导致组件重新渲染。
这里有一个代码沙箱来演示: https : //codesandbox.io/s/react-router-dom-dynamic-basename-forked-hnkk0?file=/index.js
您可以悬停或检查沙箱中的链接,以验证它们的href
值在更改基本名称后是否正确更新。 如果您从Router
删除key
属性,您还可以看到href
不会更新。
import React, { useState } from "react";
import { render } from "react-dom";
import { BrowserRouter, Link } from "react-router-dom";
const Root = () => {
const [count, setCount] = useState(1);
const basename = `basename-${count}`;
return (
<BrowserRouter basename={basename} key={basename}>
<Link to="/link1">Link 1</Link>
<br />
<Link to="/link2">Link 2</Link>
<br />
Current basename: {basename}
<br />
<button onClick={() => setCount(count + 1)}>change basename</button>
</BrowserRouter>
);
};
render(<Root />, document.getElementById("root"));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.