skip to Main Content

As the title asks, is there a recommended method for using:

username.domain.com/event/id/

Where I can ask React to reference both id and username as parameters?

As of now

Currently I can obtain id fine using React router (or any parameter after the domain name in the url).

App.js

import { BrowserRouter as Router, Route, Routes } from "react-router-dom";


<Router>
    <Routes>
        <Route path="/event/:id/"
            element={<>
                <EventComponent />
            </>}
        />
    </Routes>
</Router>

EventComponent.jsx

import { useParams } from 'react-router-dom';
let params = useParams();
let eventID = params.id;
// I can now use eventID to reference what was in the url

I can catch server subdomains in my nginx.conf. This is what I use to reach my React app (not a wildcard subdomain yet, but that’s not much of a change and not the problem):

server {

    listen      443 ssl;
    charset utf-8;
    client_max_body_size 10M;

    server_name         domain.com;
    
    root                "/usr/share/nginx/html/domain.com/public_html";

    location / {
        index            index.html;
        try_files $uri $uri/ /index.html?/$request_uri;
    }

    location /sw.js {
        add_header Cache-Control "no-cache";
        proxy_cache_bypass $http_pragma;
        proxy_cache_revalidate on;
        expires off;
        access_log off;
    }
    
}

Problem

But I don’t know a clean way to pass subdomains to React without rewriting the url in nginx so that the subdomain is becomes part of the url after the domain. This is not a scenario that’s desired.

(the following is an edit added to be more specific about the problem:)

I’m aware of getting the subdomain from window.location.hostname and splitting it to obtain a string, but I’m seeking clarity on whether this (or another method) is the most desired and won’t have caveats that can be better avoided.

To illustrate my hestitation, I could also just get the id parameter from window.location, but I don’t, as it appears to be typical to use useParams in react to do so. I’m always learning and, in doing so, try not to pick up bad habits.

Relevant criteria

As mentioned, I don’t want to rewrite the domain from the above url into something like domain.com/event/id/username/

The structure of the url and presenting it as the original, to the user, is important.

Secondly, the subdomain is a wildcard. It won’t be a fixed string. I can process this fine in nginx but it’s important that a solution allows for a dynamic string.

2

Answers


  1. If username.domain.com is the public url, I don’t quite see why you have to pass this to react, surely you can just interrogate the domain name from the browser directly.

    If not, please add info with an example of the public and local (to nginx) domains and maybe elaborate on some of the reverse proxy rules and I’ll remove the answer / attempt to update.

    EventComponent.jsx

    import { useParams } from 'react-router-dom'
    const params = useParams()
    const eventID = params.id
    const username = window.location.hostname.split('.')[0]
    

    Working example of using this method in React:

    const Link = ReactRouterDOM.Link
    const Route = ReactRouterDOM.Route
    
    class ArticleComponent extends React.Component {
      constructor(props) {
        super(props)
        this.hostname = window.location.hostname
        this.username = window.location.hostname.split('.')[0]
      }
      render() {
        return (
          <div>
            <p>Username fetched from parent App and passed as prop in the standard React manner</p>
            <p><i>Note: It will say `stacksnippets` as the username, because there are only two levels in the hostname. If there were 3 levels eg, `user1.domain.com`, the username would be `user1`</i></p>
            <p>Hostname: <b>{this.hostname}</b></p>
            <p>Username via props: <b>{this.props.username}</b></p>
            <p>Username from component directly: <b>{this.username}</b></p>
            <p>Article ID: <b>{this.props.match.params.id}</b></p>
          </div>
        )
      }
    }
    
    class App extends React.Component {
      constructor(props) {
        super(props)
        this.props.username = window.location.hostname.split('.')[0]
      }
      render() {
        return (
          <ReactRouterDOM.HashRouter>
            <ul>
              <li><Link to="/">TO HOME</Link></li>
              <li><Link to="/articles/link1">TO /articles/link1</Link></li>
              <li><Link to="/articles/link2">TO /articles/link2</Link></li>
            </ul>
            <Route path="/" exact component={Home} />
            <Route path="/articles/:id" render={(props) => (<ArticleComponent username={this.props.username} {...props}/>)} />
          </ReactRouterDOM.HashRouter>
        )
      }
    }
    
    const Home = props => <div><h1>HOME</h1><p>Click a link to navigate</p></div>
    
    ReactDOM.render(<App />, document.querySelector('#root'))
    <script src='https://unpkg.com/[email protected]/umd/react.production.min.js'></script>
    <script src='https://unpkg.com/[email protected]/umd/react-dom.production.min.js'></script>
    <script src='https://unpkg.com/[email protected]/umd/react-router-dom.min.js'></script>
    <script src='https://unpkg.com/[email protected]/babel.js'></script>
    <div id='root'></div>
    Login or Signup to reply.
  2. A subdomain is something only the Webserver should handle.
    React router is not able to distinguish between them.

    There are multiple ways of achieving the desired outcome, I’ll share my thoughts based on previous experiences.

    Note: This assumes all the subdomains should point to the React index.html


    Native + Props

    Since all the subdomains will trigger the same React app, we can use the regular Javascript way of retrieving the subdomain, this can be passed to deeper components as a normal prop.

    # App.js
    const subdomain = // prefered way of retreiving subdomain;
    <EventComponent subdomain={subdomain} />
    
    # EventComponent
    let params = useParams();
    let eventID = params.id,
        subdomn = props.subdomain
    

    Query Parameter

    (I’ve used this in production to move a header to a query parameter that is removed instantly so the user can’t see it, works great)
    You can let Nginx add a query parameter with the subdomain (../?user=foobar), this can easily be parsed with Javascript, to ensure the user does not notice this, you can remove the param after the page loads, the user won’t even notice

    server_name  ~^(?<subdomain>.+).example.com$; 
    return       301 http://example.com$request_uri?user=$subdomain;
    

    Cookie

    The same idea as above, but instead off using query parameters, you can inject the subdomain into a cookie and read it using Javascript

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search