繁体   English   中英

react-router-dom 中带有 BrowserRouter 的动态基名

[英]dynamic basename with BrowserRouter in react-router-dom

请我在构建多租户 SaaS 解决方案时遇到问题。 对于每个租户,我希望他们使用一个子域,这样我就可以从 url 获取子域,调用 REST api 返回有关该租户的数据。

例如,

  1. 管理员(完全是另一个应用程序 - 管理员应用程序)创建一个具有域名的租户: tenant1
  2. 在我的本地系统上的租户应用程序中,我能够转到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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM