How to prioritize the route in React? - javascript

I'm making React app, and I have some Routers.
const App = () => {
return (
<div>
<Header/>
<div>
<Route path="/LogIn" render={() => <LogIn />} />
<Route path="/Shop" render={() => <GoodsContainer />} />
<Route path="/Delivery" render ={() => <Delivery />} />
</div>
<Footer />
</div>
)
}
When I open my page for the first time, there're only Headercomponent and Footer component, and It's logically because the url has not contain pathes which I have set to the Routes.
So, my question is how to show always , for example the Route <Route path="/Shop" render={() => <GoodsContainer />} /> when the user open the site.
Redirect isn't my solution.

path prop could either be a string or an array of strings. You can define multiple paths for GoodsContainer component using an array of strings as a value for path prop
<Route path={["/", "/Shop"]} render={() => <GoodsContainer />} />
and don't forget to either use exact prop on Route component or wrap all Route component with Switch component otherwise / path will match all other routes.

You can check #Yousef answer for this , Also if you arent passing any props, then do this instead. Don't forget to give the exact
<Route path={["/", "/Shop"]} exact render={GoodsContainer} />
But if you are passing then do this
<Route path={["/", "/Shop"]} exact render={(props)=> <GoodsContainer {...props} />} />

Related

How to realize <Route children={({match})} => ... /> in a react-router-dom v6?

I have a modal which depended on a url.
my modal in jsx
<Route
path={`/preview/${params.id}`}
children={({match}) => {
return (
<ModalWindow
modalVisible={Boolean(match)}
onCloseWindow={onCloseWindow}
modalContent={modal}
/>
)
}}
/>
I am getting an error A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.
But I already wrapped all my app in a tag.
export default function AppRouter() {
return (
<Routes>
<Route
path={"/home"}
element={<HomeApp />}
/>
<Route
path={"/preview/:id"}
exact
element={<HomeApp />}
/>
<Route
path={"/fullInfo/:id"}
exact
element={<HomeApp />}
/>
<Route
path={"*"}
render={<Navigate to="/home"/>}
/>
</Routes>
)
}
P.s I am new in react-router-dom of the new version.
You have to wrap the rendered element in the element prop of your Route.So instead of :
<Route
path={"*"}
render={<Navigate to="/home"/>}
/>
Do this:
<Route
path={"*"}
element={<Navigate to="/home"/>}
/>
It is the same for the modal Route, you should wrap the component in the element prop of the Route

How to avoid re-initializing component when multiple linked routes use same component

I have a react-router-dom component that was all working fine in v5, and I have since upgraded to v6. In the below router structure, I have a single component that is accessed via different routes. This view has a playback feature that updates the URL when playback is stopped resulting in a foo/<fooId>/<time> url structure, and a means to link to something in the list with bar/<barId>. Both of these render the same component, that uses the params as need be and can handle both entry points.
The issue I'm seeing since moving to v6 is it will refresh if switching from foo/<fooId>/<time> to bar/<barId> or viceversa. Same happens if I click a link to bar/<barId> while on foo/<foodId>/time. It's the same component, and simply updated the browser URL in the past (used to use history.pushState and now use navigate (from useNavigate), I tried adding a replace param, etc., but it still re-mounts the entire component.
How can I avoid this? I can only think to re-structure the pages, but there's a bunch of bookmarks out there that will be very unhappy, haha.
<Route
path="/foo"
element={<AuthedRoute authState={authState} element={<Bar />} />}
>
<Route
path=":fooId"
element={<AuthedRoute authState={authState} element={<Bar />} />}
/>
<Route
path=":fooId/:timestamp"
element={<AuthedRoute authState={authState} element={<Bar />} />}
/>
</Route>
<Route path="/bar">
<Route
path=":barId"
element={<AuthedRoute authState={authState} element={<Bar />} />}
/>
</Route>
AuthRoute:
function AuthedRoute({ authState, element }) {
const location = useLocation()
const { isLoggedIn } = authState
return isLoggedIn ? (
element
) : (
<Navigate
to="/login"
state={{
from: location,
}}
/>
)
}
Similar structure to the example here
Shoot, ok, I hadn't noticed that you had nested "/foo" and "/bar" routes. That changes things a bit. I was able to reproduce the issue of switching between "/foo" and "/bar" routes. I still suggest converting the AuthedRoute into a layout component and rendering an Outlet for nested routes you want to protect.
function AuthedRoute({ authState }) {
const location = useLocation();
const { isLoggedIn } = authState;
return isLoggedIn ? (
<Outlet />
) : (
<Navigate
to="/login"
state={{
from: location
}}
/>
);
}
Next is to configure/structure your routes so the are correctly nested. The following structure seems to work as you are expecting.
<Routes>
<Route element={<AuthedRoute authState={authState} />}>
<Route path="/foo/*">
<Route index element={<Bar />} />
<Route path=":fooId" element={<Bar />} />
<Route path=":fooId/:timestamp" element={<Bar />} />
</Route>
<Route path="/bar/*">
<Route path=":barId" element={<Bar />} />
</Route>
</Route>
<Route path="/login" element={<Login /* auth props? */ />} />
</Routes>
For testing when Bar component was mounted vs rendered (an id prop was passed to each to identify them):
const Bar = ({ id }) => {
useEffect(() => {
console.log("Bar MOUNTED!!", { id });
}, []);
useEffect(() => {
console.log("Bar Rendered!!", { id });
}, [id]);
return <h1>Bar</h1>;
};
After authenticating, use the links to navigate between all the different routes and note when "Mounted" vs "Rendered" logs.
Here's my running codesandbox:

React nested route page not rendering properly as expected

I created this react component which has some nested routes. The problem is that the nested page component is either not rendering at all despite the URL changes or just returns a blank page.
I tried the suggestions from other posts like adding/removing exact in the parent route, but it's still not working.
Below are my codes:
// the parent component
<div className="App">
<Router>
<Navbar />
<Switch>
<Route exact path="/" render={() => <MyPage accessToken={accessToken} />}/>
<Route path="/editing/:playlistId" render={(props) =>
<EditingPlaylist {...props} accessToken={accessToken} />} />
</Switch>
</Router>
</div>
//the child component EditingPlaylist
render() {
const { pathname } = this.props.location;
return (
<div className="editing">
<Switch>
<Route exact path={pathname} render={() =>
<Searchbar accessToken={this.props.accessToken} />} />
<Route path={`${pathname}/test`} component={<p>Test</p>} />
<Route path={`${pathname}/album/:albumId`} render={
(props) => <AlbumPage {...props} accessToken={this.state.accessToken} />} />
<Route path={`${pathname}/artist/:artistId`} render={
(props) => <ArtistProfile {...props} accessToken={this.state.accessToken} />} />
</Switch>
</div>)
}
export default withRouter(EditingPlaylist);
Use url and path:
const { url, path } = this.props.match
to defined nested routes.
So, in nested routes:
<Switch>
<Route
exact
path={path} // HERE
render={() => <Searchbar accessToken={this.props.accessToken} />}
/>
...
</Switch>
There is a difference between url and path:
url: It is what is visible in the browser. e.g. /editing/123. This should be used in when redirecting via Link or history.push
path: It is what matched by the Route. e.g. /editing/:playlistId. This should be used when defining (nested) paths using Route.
From docs:
path - (string) The path pattern used to match. Useful for building nested <Route>s
url - (string) The matched portion of the URL. Useful for building nested <Link>s

How can I render a component in React to 2 different components?

I'm working on a ReactJS project. I have 3 components in the main page "Index component" as follows,
Nav-
Featured-
Footer
My Nav component has 2 links to 2 different components.
My Switch is as follows,
<Switch>
<Route path="/home" component={props => <Index {...props} />} />
<Route path="/register" component={Register} />
<Route path="/login" component={Login} />
<Route path="/cart" component={Cart} />
<Redirect from="/" to="home" />
</Switch>
I also have my Index component as follows,
<React.Fragment>
<Search />
<Nav history={history} />
{this.homePageComponents()}
<Route
path="/home/bedding"
component={props => (
<Bedding beddingProducts={this.beddingProducts()} {...props} />
)}
/>
<Route
path="/home/bath"
component={props => (
<Bath bathProducts={this.bathProducts()} {...props} />
)}
/>
<Route path="/home/search" component={Search} />
</React.Fragment>
I'm trying to render the Nav component to both Bath and Bedding products but whenever I import it and use it there it gives me an Error saying this.props.history.replace is undefined.
This is the project's link.
https://github.com/MaxOffline/beetle
I think you can solve your issue with using "withRouter" wrapper component which react-router provide to wrap your Nav component.
https://reacttraining.com/react-router/web/api/withRouter
If you console.log(this.props) in the render method of nav.jsx you'll see that it contains a history object but that there is no replace method on that object.
You may be looking for the this.props.history.push method?
I found a very simple way to fix the problem.
All I needed to do is render components to the homepage conditionally so I simply added the following helper method to my "Index" Component.
homePageComponents = () => {
const featuredProducts = this.state.products.filter(
product => product.featured === true
);
if (this.props.history.location.pathname === "/home") {
return <Featured featuredProducts={featuredProducts} />;
}
};

Nested React Router : hide parent component on showing nested child component

Being a beginner in reactJS, I want to know how to hide parent component when i route to child component URL
Assume a scenario:
User is at "/house" as this:
<Route path="/house" component={House} />
when user clicks a house grid he navigates to "/house/flat/:flatID". Inside House component
<Route
path={`${this.props.match.url}/flat/:flatId`}
render={() => <div>Each Flat details</div>}
/>
then both child and parent components are visible like this:
So what i want is to show only flat component when user navigates to "/house/flat:FlatId". Please suggest me anything that helps ! Any links to article so that i can learn and achieve such functionality.
Code:
App.js
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/account" component={Account} />
<Route path="/gharjagga" component={GharJagga} />
</Switch>
House.js
onGharGridClick= id => {
<Redirect to={`${this.props.match.url}/flat/${id}`} />;
};
return (
<Route
path={`${this.props.match.url}/flat/:fkatId`}
render={() => <div>Ghar Each</div>}
/>
);
You can achieve it different ways
define routes in the parent component, I think this is the best option.
<Switch>
<Route path="/account" component={Account} />
<Route path="/house/flat/:flatId" component={FlatComponent}/>
<Route path="/house" component={House} />
<Route path="/" component={Home} />
</Switch>
Note: instead of using exact, order your routes based on priority, that will make the route to redirect to next matching route if any typo in the route entered
You can make House as separate route component, and nest the routes inside that component
// Routes
<Switch>
<Route path="/account" component={Account} />
<Route path="/house" component={House} />
<Route path="/" component={Home} />
</Switch>
// House component
class House extends React. Components {
render() {
return (
<Switch>
<Route path="/house/flat/:flatId" render={() => <div>Each Flat details</div>} />}/>
<Route path="/house" component={HouseGridComponent} />
</Switch>
)
}
}
you can check whether the route has flatId and hide the elements, in your House component you can check this.props.match.params.flatId, if the flatId is set you can hide that House Component.
// House Component
class House extends React. Components {
render() {
return (
<div>
{
!this.props.match.params.flatId?
<h1>House Component</h1>:
null
}
<Route path={`${this.props.match.url}/flat/:flatId`} render={() => <div>Each Flat details</div>} />
</div>
)
}
}
The solution is to raise "/house/flat/:flatId" to the same level as "/house".
<Switch>
<Route exact path="/" component={Home} />
<Route path="/account" component={Account} />
<Route path="/house/flat/:flatId" render={() => <div>Each Flat details</div>}/>
<Route path="/house" component={House} />
</Switch>

Categories

Resources