Please I have an issue building a multi-tenant SaaS solution. For every tenant, I want them to use a subdomain, so i can get the subdomain from the url, make a call to a REST api that returns data about that tenant.
For example,
tenant1. tenant1.localhost:3000. I get the url, and get the domain name. I then make a call with the domain to get the theme of tenant (this is stored in localStorage).Unfortunately, we deploy on k8 in my company and so I couldn't mimic this behavior. So i have been advised by the devOps team to use subdomain in the context, thereby having localhost:3000/tenant1. Remember the tenant is dynamic, so i tried this:
<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>
The solution above however makes my url to localhost:3000/:tenant/login
Please how can i use dynamic basename in the router, so it can accept:
localhost:3000/tenant1
localhost:3000/tenant3
localhost:3000/tenant2 etc.
It can allow any, my app handles wrong domain inputted
This worked for me using react >16 and 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>
    );
};
                        Here's a codesandbox and the utility I wrote:
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;
};
                        I finally used dynamic tenant with the following code
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)
                        You can render updates to your router's basename by using the key property. Any changes to the key value will cause the component to re-render.
Here's a code sandbox to demo: https://codesandbox.io/s/react-router-dom-dynamic-basename-forked-hnkk0?file=/index.js
You can hover or inspect the links in the sandbox to verify that their href values are correctly updating after changing the basename. You can also see that the hrefs won't update if you remove the key property from Router.
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"));
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With