0

In my React application, a Route in the nav menu points to /persons url. When clicked, the rendered page shows all the available persons, let's say in a table. The user can then select a particular person to see the detail at the url /persons/:personId. However, when there is only one user available, the requirement is to directly show the person detail, and bypass the step to show table of persons.

In the React Component, I am trying to identify if there is only one person available in the useEffect() and using react-router-dom's navigate(useLocation().pathname + "/" + personId).

Here is the relevant code snippets.

...
<Route path="/persons/:personId?" element={<Persons />} />
...
const { personId } = useParams();
const persons = // via some service call;
useEffect(() => {
    if (!personId && persons.length === 1) {
      useNavigate()(useLocation().pathname + "/" + persons[0].id);
    }
}, []);
...

With this I receive => 'Too many re-renders. React limits the number of renders to prevent an infinite loop.'

Here are my questions

  • How to navigate to the same page having added a parameter from within the page?
  • What is the best practice around this use-case? Should I render another component for /persons/:personId?
Gro
  • 1,613
  • 1
  • 13
  • 19
  • You cant use a hook inside an effect `useNavigate` and `useLocation`. Right now you redirect on every page load. You need logic to check if the `claimId` already is part of the url – Vincent Menzel Jun 05 '23 at 13:06
  • You should have 2 components, one for the list and another for a single user. Then the single user component can determin what to show – 0stone0 Jun 05 '23 at 13:24
  • Getting personId from useParams in line 1 and using the same in the if condition in line 4 is exactly there for what you are suggesting. – Gro Jun 05 '23 at 13:24
  • Also, if I take out useNavigate()(navurl) out of useEffect, react throws following 'You should call navigate() in a React.useEffect(), not when your component is first rendered.' suggesting I must use the opposite of what you (Vincent) are suggesting. – Gro Jun 05 '23 at 13:31
  • There's not really enough details to provide a sufficient solution. Please [edit] to include better details and a more complete [mcve]. – Drew Reese Jun 05 '23 at 15:47

1 Answers1

0

What is the best practice around this use-case? Should I render another component for /persons/:personId?

How about defining 2 Routes:

<Route path="/persons" element={<PersonList />} />
<Route path="/persons/:personId" element={<PersonDetails />} />

In <PersonList /> you choose one of these actions:

  1. If there are more then 1 users, show them all in a list
  2. If there's just one, navigate to the <PersonDetails /> page
    if (persons.length === 1) {
        useNavigate()(useLocation().pathname + "/" + persons[0].id);
    }
    
    // Otherwise, `map()` each user
    

In <PersonDetails /> you show the info based on :personId

0stone0
  • 34,288
  • 4
  • 39
  • 64
  • This definitely is one option, I know, but is this a best practice? Usually, both these paths are better ratified in one Route. – Gro Jun 05 '23 at 13:35
  • 1
    Why? I've learned to use React Router as a single purpose page. Listing users isn't the same as showing user details and should be seperate components. – 0stone0 Jun 05 '23 at 13:37