在react-router-dom中使用BrowserRouter动态基本名称

Lat*_*fah 11 javascript frontend reactjs react-router-v4 react-router-dom

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

例如,

  1. 管理员(完全是另一个应用程序 - 管理应用程序)创建一个域名为 的租户:tenant1
  2. 在本地系统上的租户应用程序中,我能够访问tenant1.localhost:3000. 我获取了 url,并获取了域名。然后,我与域进行调用以获取租户的主题(这存储在 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>
Run Code Online (Sandbox Code Playgroud)

然而,上面的解决方案使我的 url 为 localhost:3000/:tenant/login

请问我如何在路由器中使用动态基本名称,以便它可以接受:

localhost:3000/tenant1 localhost:3000/tenant3 localhost:3000/tenant2ETC。

它可以允许任何,我的应用程序处理输入的错误域

Lat*_*fah 11

我终于使用了以下代码的动态租户

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)
Run Code Online (Sandbox Code Playgroud)


dze*_*zed 10

这对我使用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>
    );
};
Run Code Online (Sandbox Code Playgroud)


tuf*_*uff 5

basename您可以使用该属性来呈现对路由器的更新key。对键值的任何更改都会导致组件重新渲染。

\n

这是演示的代码沙箱:\n https://codesandbox.io/s/react-router-dom-dynamic-basename-forked-hnkk0?file=/index.js

\n

您可以将鼠标悬停或检查沙箱中的链接,以验证它们的href值在更改基本名称后是否正确更新。您还可以看到,如果您从 中删除该属性,则hrefs将不会更新。keyRouter

\n
import React, { useState } from "react";\nimport { render } from "react-dom";\nimport { BrowserRouter, Link } from "react-router-dom";\n\nconst Root = () => {\n  const [count, setCount] = useState(1);\n  const basename = `basename-${count}`;\n\n  return (\n    <BrowserRouter basename={basename} key={basename}>\n      <Link to="/link1">Link 1</Link>\n      <br />\n      <Link to="/link2">Link 2</Link>\n      <br />\n      Current basename:\xc2\xa0{basename}\n      <br />\n      <button onClick={() => setCount(count + 1)}>change basename</button>\n    </BrowserRouter>\n  );\n};\n\nrender(<Root />, document.getElementById("root"));\n
Run Code Online (Sandbox Code Playgroud)\n