React Router Dom Pathname keeps nesting - reactjs

I have a React app in which a search options is included in the navbar, and can be accessed anywhere in the app. Whenever a user searches and then clicks on one of the products show, it should send them to a detail view of that product.
The problem I am facing is with routing. Whenever I search and click in the product for the first time, it correctly redirects to, as an example, http://localhost:3000/catalogue/women/sportive-shoes-sneakers/sneakers--low-top-sneaker/292487. However, if once I am in that route I try to go send the user to another product, it formulates the url like this: http://localhost:3000/catalogue/women/sportive-shoes-sneakers/sneakers--low-top-sneaker/catalogue/men/denim-pants/jeans/293140. As you can see, it's nesting the pathnames one after the other.
My code looks like this:
this.state.displayProducts.map((product, index) => {
return (
<NavLink strict to={{
pathname: `catalogue/${StringUtil.getUrlFromString(product.line)}/${StringUtil.getUrlFromString(product.familyName)}/${StringUtil.getUrlFromString(product.subfamilyName)}/${product.id[0] || product.id}`,
selectedProduct: product
}} key={index}>
<div className="catalogue-productlist-product" onClick={this.props.wipeInput && this.props.wipeInput}>
<img src={product.images && product.images[0] ? product.images[0].replace('{authorization}', this.props.token) : this.props.placeholder}
alt="Category" onError={this.imgError} />
<div>
{product.productName}
</div>
</div>
</NavLink>
)
})
And my Route like this:
<Route
exact path="/catalogue"
render={(props) => (
window.location.search.length > 0 ?
<ProductList />
:
<Slider
{...props}
categories={this.props.categories}
/>
)}
/>
<Route
exact path={`/catalogue/search/:qs`}
component={ProductList}
/>
<Route
exact path={`/catalogue/:line/:family?/`}
render={(props) => (
<Slider
{...props}
categories={this.props.categories}
/>
)} />
<Route
exact path={`/catalogue/:line/:family/:subfamily`}
component={ProductList} />
<Route
exact path={`/catalogue/:line/:family/:subfamily/:product`}
component={ProductDetail} />
How would one go about it working as intended? ie: no matter the current route, the user should always be sent to wherever the navlink send them.

The problem lies here in your pathname, you should always consider add a leading slash in your pathnames just like this:
...
pathname: `/catalogue/${StringUtil.getUrlFromString(product.line)}/${StringUtil.getUrlFromString(product.familyName)}/${StringUtil.getUrlFromString(product.subfamilyName)}/${product.id[0] || product.id}`
...
If you don't use this leading slash in your link navigation it will always append the path you provided to the previous path that you provided, so it will make your first redirect nice and tidy then the upcoming ones will append to the existing path that you are in right now.
NOTE: If you always want to change the whole directory with each product selected consider adding leading slash in your pathname, otherwise, you should use an alternative way.

I think i know what the problem is, I am not 100% sure but going to go out on a limb, because I have encountered similar issues in the past, I think you need to add a '/' to the pathname value before 'catalogue'.
...
return (
<NavLink strict to={{
pathname: `/catalogue/${StringUtil.getUrlFromString(product.line)}/${StringUtil.getUrlFromString(product.familyName)}/${StringUtil.getUrlFromString(product.subfamilyName)}/${product.id[0] || product.id}`,
...
Because it is not prefixed with '/', it is appending the path to the current path rather than starting it from the beginning.

Related

React-Router different animation for each route

I'm struggling to make React-Router work well with CSSTransition, which seems to be the defacto library for this around the web.
I'm using React-Router v6 without any issue. I'm not sure if the issue is due to that or not being that it is more recent.
Goal
My goal is to animate between my different route with an animation that plays when clicked-in and another that plays when clicked-out.
In term of style, I'm just looking at a simple "Slide-in" animation. Where my first component will slide-in-from-bottom and slide-out-to-bottom before the second component will slide-in-from-right and eventually slide-out-to-right when clicked out. and things like that.
Issues
I can't believe this is so hard to put into practice. I am definitely not the first one that wants to do this.
I'm open to any suggestion that'll work and that uses React-Router.
I have tried to use CSStransition in every way possible so far.
I tried without it and tried making a new functional component that takes in "Location" and "PreviousLocation"(Custom State) in combination with useEffect to animate the div around the route before it is rendered but was way over my head and couldn't make it happen. Not sure how to prevent rendering while keeping what's already rendered and wait for the animation to finish to allow the render.
I would gladly take any help and any method that works at this point.
thanks.
My bare code just for reference (I have discarded everything I've tried and started fresh):
const App = () => {
const location = useLocation();
return (
<div className="app">
<section className="main">
<Routes>
<Route index element={<Home />} />
<Route path="home" element={<Home />} />
<Route path="marketplace" element={<Marketplace />} >
<Route index element={<Listing />} />
<Route path="listing" element={<Listing />} />
<Route path="cart" element={<Cart />} />
</Route>
</Routes>
</section>
<nav className="main-nav">
<ul>
<li>
<NavLink to="/home" className={(navdata) => (navdata.isActive ? 'active' : 'none')} >
<span className="nav-text">Home</span>
</NavLink>
</li>
<li>
<NavLink to="/marketplace" className={(navdata) => (navdata.isActive ? 'active' : 'none')} >
<span className="nav-text">Store</span>
</NavLink>
</li>
<li>
<NavLink to="/aboutus" className={(navdata) => (navdata.isActive ? 'active' : 'none')} >
<span className="nav-text">About Us</span>
</NavLink>
</li>
<li>
<NavLink to="/user" className={(navdata) => (navdata.isActive ? 'active' : 'none')} >
<span className="nav-text">My Account</span>
</NavLink>
</li>
</ul>
</nav>
</div>
);
};
The key part of a solution to creating transitions between routes is dealing with exit transitions, and making sure the old route doesn't disappear instantly so we have time to see the exit. By passing a function as the child of Route, we are able to achieve that.
To achieve a unique transition on each Route we simply need to provide each Route with it's own CSSTransition and set up the css properties for each transition.
A single Route would look like this:
<Route path="/user">
{({ match }) => (
<CSSTransition
in={match != null}
classNames="spin"
timeout={500}
unmountOnExit
>
<div className="absolute">
<Marketplace />
</div>
</CSSTransition>
)}
</Route>
And here is a full example set up in codesandbox with four example of routes with unique transitions. They are not very pleasing animations, but are designed to show the concept clearly.
This page has some great info about how to do this and what potential issues to watch out for, such as the need to use absolute or fixed positioning:
Exit transitions will cause the content of routes to linger until they disappear, which might pose some styling challenges. Make sure that routes don't affect each other's layout, for example you can remove them from the flow of the document by using absolute or fixed positioning.

NavLink exact prop not working for react-router-dom 6

I am currently using
"react-router": "^6.0.0-beta.0",
"react-router-dom": "^6.0.0-beta.0",
The problem with NavLink of react-router-dom that i am facing now is that the root path "/" is always active, other paths are of no problem and they are being active and inactive during toggle, its just the root path that is giving me trouble, i have searched and tried many solutions. but nothing worked.
Use "exact" and "exact={true}" both, but no success.
Used this:
<NavLink
className="iconContainer"
exact={true}
to="/"
activeClassName="isActive"
>
<span className="menu-title">Home</span>
</NavLink>
and Also this:
<NavLink
className="iconContainer"
exact
to="/"
activeClassName="isActive"
>
<span className="menu-title">Home</span>
</NavLink>
I have been stuck in this situation for past two days, and still no success in finding any solution.
Any help will be appreciated, thanks
Edit:
My routes
<Routes>
<Route
exact
path="order/:orderId"
element={<OrderDetails />}
></Route>
<Route
exact
path="orders"
element={<Orders />}
></Route>
<Route
exact
path="/"
element={<Home />}
></Route>
</Routes>
Exact param will no longer working on NavLink component. In version 6 Beta they have included a new param called: end
With this simply approach you just need to pass end param for your NavLink component and exact to you Route
<NavLink end to="/">
Go to Home
</NavLink>
When you write end="another-class-active" you can change your active className which is active by default.
As #Greg Wozniak mentioned end is a boolean so you can't change active class name with this, instead of this you can pass a function to className:
className={({ isActive }) =>
isActive ? 'activeClassName' : undefined
}
For more information read this:
https://reactrouter.com/docs/en/v6/api#navlink
Working example:
https://codesandbox.io/s/vigorous-thompson-e7k8eb
Note that this is still version Beta so we need to wait for some fixes and official releases
In 6.0.2 you can pass a function to className and that function gets a set of props. One of those props is "isActive". Here is how I solved it for the OP code:
<NavLink
className={(props) => {
return `${props.isActive ? 'isActive ' : ''}iconContainer`;
}}
end
to="/"
>
<span className="menu-title">Home</span>
</NavLink>
Also note that the class "active" is automatically set by the
NavLink.
Also note the use of end: "If the end prop is used, it will ensure this component isn't matched as "active" when its descendant paths are matched. For example, to render a link that is only active at the website root and not any other URLs"
However this how I did it, you don't have to use exact in the case of NavLink as said by the official docs, LINK TO THE DOCS
<NavLink to="/service" className='turner'>
Services
</NavLink>

How to conditionally render a component when I am at my index route with Reach-Router (or my top level route)?

I want a list to be hidden from the user if the url is not '/'. This list renders at the top level and consists of many links. Whenever I navigate back to '/' (index route) I want to show the list again. How can I use reach router most effectively to listen to this location and change the state accordingly so I can hide/show my article list and hide/show the article with the appropriate path?
I tried using the navigation component and played around with the LocationProvider component but am currently stuck.
The below component is wrapped in a Router with path '/*'
<div>
<Header />
<div className='App'>
<Slide
direction='right'
in={true}
timeout={{
appear: 0,
enter: 400,
exit: 0
}}
mountOnEnter
unmountOnExit>
<List>{getArticlesList()}</List>
</Slide>
</div>
<Router>{getArticles()}</Router>
</div>
Using react router you have to specify an exact path.
<Router>
<Route exact path="/" component={List} />
</Router>
If you wanted something to display on all routes you could remove the keyword exact and use it like
<Router>
<Route path="/" component={List} />
</Router>
I solved this problem by using the useEffect hook and checking the pathname via props.location.pathname to see if the user is at the path '/'. If the user is at the top path, then I show the list, if not I hide the list.

React Router v4: <Route> component unable to match urls with question marks

I'm using a React.js app as a widget inside a Wordpress admin area. The way some users configure wordpress urls can use query parameters to set the page view, for example:
domain.com/wpFolder/wp-admin/options-general.php?page=settingspage
I want to be able to set my Links and Routes to conform to this structure so that page reloads don't break. I am unable to do this, adding slashes/subfolders is fine but the moment I add ? the <Route /> no longer matches. Example:
<StyledMaterialLink // This is a <Link /> wrapped by Styled Components
component={RouterLink}
to={`/wptest2/wp-admin/options-general.php?`}>
<Tab
label="See Current Coupons"
value={seeCurrentCoupons}
onClick={() => {
console.log(location.href, `=====location.href=====`);
setAdminView(seeCurrentCoupons)
}}
/>
</StyledMaterialLink>
<Route
path={`/wptest2/wp-admin/options-general.php?`}
render={props => {
return (
<CurrentCouponChannel.Provider
value={state.currentCouponsAndTargets}>
<ViewCoupons />
</CurrentCouponChannel.Provider>
)
}}
/>
Eventually I would like the <Route path /> above to end with &section=view-coupons as well.
Is it possible to hardcode query string params this way to work after reloading with my framework?
Search parameters are not part of the path. You can access those values through props.location
<Route
path={`/wptest2/wp-admin/options-general.php`}
render={props => {
// do something with props.location.search
The library https://www.npmjs.com/package/query-string is helpful here.

react-router four won't let me redirect back to home?

I have something like this using react-router 4:
<Route exact path="/" children={({match}) => (
<TransitionGroup component={firstChild}>
{match && <Home match={match} />}
</TransitionGroup>
)}/>
<Route exact path="/idea/:id" children={({match}) => (
<TransitionGroup component={firstChild}>
{match && <IdeaDetails match={match} />}
</TransitionGroup>
)}/>
<Redirect from='*' to='/' />
Basically if someone types in a url other than idea/:id, I want to redirect them back to the home page. When I run this code, it seems to do I expect. Except in the developer consoles, I see this warning
Warning: You tried to redirect to the same route you're currently on:
"/"
Is there a way to define the routes that I have without tripping this warning? Is there a way to tell react router to not process any subsequent route rules once one of them has been found?
Is there a way to tell react router to not process any subsequent route rules once one of them has been found?
Yes, you need to wrap your routes in a Switch component. When your routes are wrapped in a Switch, it finds the FIRST matching route and then returns it without continuing. Without a Switch, the router will return ALL routes that match the current url.

Resources