react router useparams comes back as undefined

Viewed 3203

I'm using react-router-dom V5. A simple version of my code is: Index.tsx:

ReactDOM.render(
  <React.StrictMode>
    <Router basename={urlExtra}>
        <App />
    </Router>
  </React.StrictMode>,
  document.getElementById("root")
);

App.tsx

function App() {
  return (
    <>
      <NavBar />
      <main css={content}>
        <Switch>
          <Route exact={true} path={"/"} component={Home} />
          {Routes.map((routes: any) => (
            <Route path={routes.path} key={routes.path} component={routes.component} />
          ))}
          <Route path="*" component={NoMatch} />
        </Switch>
      </main>
    </>
  );
}

Navbar.tsx:

const NavBar: React.FC = () => {
  const { organizationId, tenantId } = useParams();
....

since my Navbar is outside of my routing pages, it never gets updated and all of the parameters stay as 'undefined' when i switch pages. How can i tell the navbar links to update when a page change updates one of those values?

1 Answers

useParams can only extract the params from routes it is contained within. It's essentially a short-cut for the useRouteMatch hook, using the combined route data for a certain depth in the component tree.

You can manually test for certain routes by creating your own instance of the route matching hook at any depth. For example:

const NavBar: React.FC = () => {
  const match = useRouteMatch({
    path: "/buildings/:organizationId/:tenantId",
    exact: true
  });
}

The value of match will be null when the route does not match, and when it does match, it returns an object which has a property that will look like this:

params: {
  organizationId: "someOrganzationId",
  tenantId: "someTenantId"
}

For more information, look at the documentation for useRouteMatch and the function matchPath which it is built on top of.

Edit:

You can use more complex paths (including regexes) to match a variety of route syntaxes. In this example, the paths Test1 and Test2 will match, but not Test3 or Tests:

function NavBar(){  
  const match = useRouteMatch('/Test:i([1-2])/:id1/:id2');
  
  const { id1, id2 } = {
    id1: match?.params.id1,
    id2: match?.params.id2
  };
  
  return match && (
    <ul>
      <li><Link to={`/Test1/${id1}/${id2}`}>Test 1</Link>
      </li>
      <li><Link to={`/Test2/${id1}/${id2}`}>Test 2</Link>
      </li>
    </ul>
  )
}
Related