Duplicate pathname issue in useLocation - reactjs

I'm making a web with react and react router.
The problem is, the pathname in useLocation() has a record of the previous page and a record of the current page.
For example, '/' on the home screen and the '/business' page on another page are contrasted together.
Also, if you refresh on the /business page and go to ‘/info’, ‘/business’ and ‘/info’ appear together.
If you look at the picture I posted above, whenever a scroll event occurs, I try to determine if the pathname (the same is the url variable) variable is ‘/’ and write logic according to the boolean value.
However, there are cases where there are two executions in the console, in the statement, with the old pathname and the current pathname.
If only url or url is taken to the console, the current result value is displayed, but the history of the previous page is also actually brought if it is suggested in the scroll event of the window.
Does anyone know a solution for this?

You may be needing the exact keyword:
When true, the active class/style will only be applied if the location is matched exactly.
<Switch>
<Route exact path="/"><Home/></Route>
<Route exact path="/accounts/login"><Login/></Route>
<Route exact path="/accounts/profile"><Profile/></Route>
</Switch>
It may be because you have an '/' route defined so that React Router couldn't interpret the URLs accurately.
Yes, applying the prop to every Route may be overkill, but it guarantees no room for bugs.

Related

How to view the list of history paths in react-router?

Is it possible to view the list of paths in the history object? I can see that there is the length but I need to see the actual paths.
The reason for this is for debugging purpose. I have 2 views (SPA) that gets displayed via their corresponding URL. But my problem is when I go from the first page to the next page and then I wanted to go back to the first page, I need to click the browser back button 2 times before it goes back to the first page. That's the reason I wanted to see what are the paths in the history object so I can check what entries are being added because as far as I can see, the code I have to add a path to the history object is straightforward:
props.history.push("/classes/" + courseId);
That's just the code so I don't know why I need 2 clicks to go back to the previous page.
Not exactly sure how to see the history stack, but you might be unintentionally rendering the page twice, so the history.push is working as intended. You can log in componentDidMount to see if it does, and be careful when using useEffect because that can cause that as well. If you're using react router check how the route is added in your app.js (for ex do <Route path="/classes/:courseId" component={courseId}> instead of <Route path="/classes/:courseId" render={()=>courseId()}>.

Is it possible to hide secret URL paths when using React Router?

I'm new to React, and have a n00b question and Googling hasn't turned up any good answers, maybe someone here knows:
With React Router or any kind of declarative routing, how do you "hide" private URLs that you don't want every user to know about? Or, if you just want to prevent someone from being able to easily enumerate all valid URLs?
Code splitting doesn't solve this (really) because the user is told what to request to get the rest of the information: I suppose you could put that URL behind authentication or some kind of restriction to prevent public access to it, but won't that cause the JS fetching the code-split import to receive an error, causing that error to bubble up and cause unintended failure behavior?
Edited to add:
The crux of my issue is wanting to essentially do <Route path="/:path"> where :path matches the entire URL path (e.g., could be foo/bar/baz) instead of just the first "part" (e.g., foo) for a URL like https://example.com/foo/bar/baz for example.
I could use <Route path="*"> and do my own URL parsing, but what if I don't want that route to actually handle the request? How do I signal "nope, I don't want this request, fall-through to the next matching Route"?
You can check if the user is authorized to see these routes and then show or hide them.
<Route path="/cities" component={City} />
<Route path="/courses" component={Courses} />
{user.hasPermission && (
<Route path="/secret" component={VerySecretPage} />
)}
If you want to go further, you can create a custom guarded route as described in this blog post.

React component not rendered when sub path is called directly

I am having a Server Side Rendered React app where I use HashRouter for react routing(v5). My Routes look like this
<HashRouter basename="/">
<Layout {...config} />
</HashRouter>
<Switch>
<Route exact={true} path="/" component={LPComp} />
<Route exact={true} path={this.props.siteBanner.Red} component={bannerPage} />
</Switch>
When I hit localhost:8888/parent/ and once it get loaded and if I hit localhost:8888/parent/banner in the same window the bannerPage component renders fine.
But I hit localhost:8888/parent/banner directly(consider in a new tab), then the component is not rendered properly.
Any ideas why this is happening?
Also to add on when I hit localhost:8888/parent/banner I can see LPComp(default route) also being loaded and then it disappears suddenly and the bannerPage component renders improperly.
Thanks in Advance
The behavior is making sense, since your routes is based on a prop/state this.props.siteBanner.Red. So the first thing is to put a console.log once you enter this component.
console.log(this.props.siteBanner.Red)
In your first case, you reach this component from its parent, this way the props mostly likely is resolved.
In your second case, you reach it directly, of course also from its parent, but most likely there's no time for the props to get resolved quickly. Couple of possibilities
useEffect is to update this variable
mouse click is required to get a value
setTimeout is used to defer
callback is used to get this variable
You can say there's 50ms delay in getting this prop resolved, but you need to dig out why yourself. Dynamic route is more advanced thing, it's easy to have permanent route.
Thank you all for your timely response, I was able to solve that issue by setting location=(req.url) from the server side configured static router. Going through this example I got the bigger picture I was missing.
https://medium.com/javascript-in-plain-english/server-side-rendering-in-react-redux-ab0af31c9c4b

Show/Hide route components in react

I am working on a React application which has routes like so:
<Switch>
<Route path="/edituser/:username" component={EditUser}/>
<Route path="/createuser/:type" component={EditUser}/>
<Route path="/listusers" component={ListUsers}/>
</Switch>
ListUsers component shows a table with pagination where each component in the table has a link which points to /edituser/:username.
I can edit users by clicking on the item in the table but as expected with react, once I go back to listusers/ the component is loaded again and I will be on the first page of users. I want to be on the page from where I accessed the user in the first place.
What is the best pattern to achieve this? I thought about passing in the page number to /edituser and then back to /listuser but then again I have to load all the paginated results again. Is local storage the only option? Any pointers are much appreciated.
There are two solutions for your problem:
1) Pass last active page ad route parameter and set your pagination accordingly.
<Switch>
<Route path="/edituser/:username" component={EditUser}/>
<Route path="/createuser/:type" component={EditUser}/>
<Route path="/listusers/:pageNumber" component={ListUsers}/>
</Switch>
on your componentDidMount you can use it to set state. For example :
const pageNumber = this.props.match.params.pageNumber;
2) Pass state prop in your routing. For example :
<Link
to={{
pathname: '/listusers',
state: { pageNumber: 1 }
}}/>
on your componentDidMount you can use it to set state. For example :
const pageNumber = this.props.location.state.pageNumber;
You could add the page number to the URL in the /listusers endpoint. Maybe something like /listusers/2 or /listusers?page=2 this way, when you hit the browser's back button, you're directly there. One last thing you could do but I wouldn't advise in this case is to store the page number in the history state.
As a rule of thumb, in order to get back, prefer using the history than using local storage.
If you really want to keep the data in memory, you can always use a store that is in a higher component (the root component for example) and keep the previous query over there. However you'll need to be careful about a lot of routing issues in such cases:
cache invalidation: the data changed on the server side in the mean time
user somehow gets back to a page with another table page number
loaded user presses the browser back button

Using multiple params with React Router?

<Route path="/:user" component={Home}>
<Route path="/:thing(/:version)" component={Thing}/>
</Route>
So, I've got two dynamic objects in my application that I'd like to be controlled by route params in react-router. Using the code above, both /0 and /0/3 take me to Home. I need /0/3 to take me to Thing. I'm not sure what I'm doing wrong here... Does react-router even support multiple dynamic params next to each other like this? I couldn't find anything in the docs.
What happens here is that you've given React Router two paths that can both match on /anything. By default then React Router matches the first one it can find.
To dig deeper, if I go to /pudding, React Router can't know if you meant /:user or /:thing. Since /:user occurs first, that option will be chosen.
You also need to make sure if nesting routes is what you want. Currently, your Thing route is nested below Home, which means that it is rendered via this.props.children in your Home component. So, for your current Thing route, Home will always be rendered too, with Thing as a child. If your Home component doesn't render this.props.children, Thing will not be shown.
I suspect you just want two different pages. What you could do to achieve that is the following:
<Router history={history}>
<Route path="/user/:user" component={Home} />
<Route path="/:thing(/:version)" component={Thing}/>
</Router>
This will make every /user/name go to the Home component, and every other /random (with an optional extra level) will go to Thing. If you wonder why in this case React Router doesn't take /user/name to the Thing route, it's because it still matches in the order your routes are specified. Because your Home route matches the requested URL, no siblings of this route are tested anymore.

Resources