reactjsreact-router-domwebpack-5

React Router: Trailing path param with decimal doesn't work


Can someone please explain why the following path doesn't work with react router 6 (BrowserRouter)

/path/1.1.1

but the following one does:

/path/1.1.1/

my route configuration is as follows. I am using declarative method i.e. useRoutes hook for defining the Routes.

const App = () => {
  const routes = useRoutes([
    {
      path: '/',
      element: <h1>Hello World</h1>
    },
    {
      path: '/app/:version',
      element: <AppUI />
    }
  ])
  return (
    <div>
      {routes}
    </div>
  )
}
const root = createRoot(document.querySelector('#app'));
root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

Whenever I am trying to hit /path/1.1.1 in Chrom, it throws error saying

Cannot get /path/1.1.1

My webpack config:

module.exports = {
  entry: './src/index.tsx',
  devtool: 'source-map',
  output: {
    publicPath: '/',
    path: path.join(__dirname, '/build'),
    filename: 'index.[hash].js',
  },
  devServer: {
    host: 'localhost',
    port: 3003,
    open: true,
    historyApiFallback: true,
  },
  module: [...],
  plugins: [...], 
}

Surprisingly, it works on codesandbox:

enter image description here

What am I missing here ?


Solution

  • It's likely the case that "/path/1.1.1" is treated as the client requesting a file "1.1.1" from directory "/path" whereas "/path/1.1.1/" is treated as the client requesting the index file from directory "/path/1.1.1". The sandbox may "cheat" a little bit since you aren't really running a server there.

    To avoid "confusion" I'd suggest passing the app version as a search parameter.

    Example:

    const App = () => {
      const routes = useRoutes([
        {
          path: '/',
          element: <h1>Hello World</h1>
        },
        {
          path: '/app',
          element: <AppUI />
        }
      ]);
    
      return (
        <div>
          {routes}
        </div>
      )
    }
    

    Assume URL path + search "/app?version=1.1.1":

    import { useSearchParams } from 'react-router-dom';
    
    const AppUI = () => {
      const [searchParams] = useSearchParams();
    
      const appVersion = searchParams.get("version"); // "1.1.1"
    
      ...
    };
    

    Or encode the version in a more URL-friendly format, say replace "." characters with "_" underscore characters, converting back to using decimals in the routed component.

    console.log("1_1_1".replaceAll("_", "."));

    Assume URL path + search "/app/1_1_1":

    import { useParams } from 'react-router-dom';
    
    const AppUI = () => {
      const { version } = useParams();
    
      const appVersion = version.replaceAll("_", ".") // "1.1.1"
    
      ...
    };