![](/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.