Nested route not being rendered - reactjs

I have:
<Switch>
<Route
exact
path={'/path/to/my/component'}
component={MyComponent}
/>
...
</Switch>
MyComponent:
return (
<div>
<h1>Here Some Text</h1>
<Link to={'/path/to/my/component/test'}>Test</Link>
<Route exact path={"/path/to/my/component/test"} component={MyOtherComponent} />
</div>
)
I am able to render MyComponent, but when I click on the link to .../test route it does not render the route below. It goes to a 404 page that I have defined.
Am i missing something?
--
So, after testing some answers, i got a problem that, the route that the link is redirecting to, does not display.
Given the following code (be aware that, all this code is already a route and is inside a <switch>).
render() {
const { match } = this.props;
return (
<div className="advanced-configuration">
<div className="advanced-configuration__content userManagement__body">
<Link to={`${match.url}/test`}>Test</Link>
<Route exact path={`${match.url}/test`} component={() => <h1>test123</h1>} />
<Route exact path={match.url} component={() => <h2>Hi from main compoponent</h2>} />
</div>
</div>
);
}
}
The statement: "Hi from main component" Gets loaded as i arrive in this route, but as i click on the test link, it falls into my "404" route, which is:
<Route component={NotFound} />
This NotFound route is sibling of MyComponent, and it is in the end of the root switch, the first one that i posted on this question.
What else can i look into, to try to see what is breaking this link?

Have you tried using match.url. Something like this. Here is what documentation says about it.
const Topics = ({ match }) => (
<div>
<ul>
<li>
<Link to={`${match.url}/rendering`}>Rendering with React</Link>
</li>
<li>
<Link to={`${match.url}/components`}>Components</Link>
</li>
</ul>
<Route path={`${match.url}/:topicId`} component={Topic} />
<Route
exact
path={match.url}
render={() => <h3>Please select a topic.</h3>}
/>
</div>
);
const Topic = ({ match }) => (
<div>
<h3>{match.params.topicId}</h3>
</div>
);

Have you tried something like :
let match = this.props.match
<div>
<h1>Here Some Text</h1>
<Link to={match.url + '/test'}>Test</Link>
<Route exact path={match.url + "/test"} component={MyOtherComponent} />
</div>
In your updated question, I am able to see the rendered JSX by clicking on the link using this markup :
<Link to={match.url + '/test'}>Show Test!</Link>
<Route path={match.url + "/test"} component={() => <h1>test123</h1>} />

Related

React Router: Redirect to a different component

There are two main links on the landing page and then when user clicks on the option it should redirect to that component and not render the component below in the same page.
But, rather than going to the next page, the component is displayed below like a navbar.
const MainRoutes = () => {
return (
<ReactRouterDOM.HashRouter>
<div className='routes'>
<nav>
<ul>
<li>
<Link to='/team-member'>Team Member</Link>
</li>
<li>
<Link to='/moderator'>Moderator</Link>
</li>
</ul>
</nav>
<Route path='/team-member' component={TeamMember} />
<Route path='/moderator' component={Moderator} />
</div>
</ReactRouterDOM.HashRouter>
);
};
const App = () => {
return (
<div className='app'>
<MainRoutes />
</div>
);
};
You need to wrap your routes in Switch:
<Switch>
<Route exact path='/team-member' component={TeamMember} />
<Route exact path='/moderator' component={Moderator} />
</Switch>
As Switch renders the first child <Route> that matches the location. Also, it renders a route exclusively (which you need).
Edit:
If you don't want to show NavBar at other components but only at index route /, you can do this:
const MainRoutes = () => {
return (
<HashRouter>
<div className="routes">
<Switch>
<Route exact path="/" component={NavBar} />
<Route exact path="/team-member" component={TeamMember} />
<Route exact path="/moderator" component={Moderator} />
</Switch>
</div>
</HashRouter>
)
}
NavBar:
function NavBar() {
return (
<nav>
<ul>
<li>
<Link to="/team-member">Team Member</Link>
</li>
<li>
<Link to="/moderator">Moderator</Link>
</li>
</ul>
</nav>
)
}

React routing link from nested component

I want to add routing to my app but the "Link" I made in a child component doesn't work onClick, but only when I refresh the page. I guess the problem is the way too much nesting but I have no idea how can I solve it.
One mention: I imported BrowserRouter as Router everywhere.
This is the file structure
This is the code spippets that related to my problem:
App component:
function App() {
return (
<Router >
<div className="App">
<Switch>
<Route exact path="/" component={NewFetch} />
<Route path="/cardID/:id" component={Details} /> //The route that doesn't work
</Switch>
</div>
</Router>
NewFetch (Main) component:
<Router> //Tried with <React.Fragment>
...
<Route path={["/cards/:name", "/cards/:filter"]}>
<Filter isLoaded={isLoaded} handleScroll={handleScroll} toScrollTop={toScrollTop} value={value}
scrollPosition={scrollPosition} jumpToTop={jumpToTop} testFilter={testFilter} />
</Route>
</Router>
Card (child 2) component from :
const Card = (props) => {
return (
<div className={props.img ? "card" : "hide"}>
<Link to={`/cardID/id=${props.id}`} > //Link that doesn't connect
<img src={props.img} alt={props.name} />
</Link>
</div>
)
};
So basically I can't connect the "Link" from a hardly nested component.
function App() {
return (
<Router >
<div className="App">
<Switch>
<Route exact path="/" component={NewFetch} />
<Route path="/cardID/:id" component={Details} /> //The route that doesn't work
</Switch>
</div>
</Router
const Card = (props) => {
return (
<div className={props.img ? "card" : "hide"}>
<Link to={`/cardID/id=${props.id}`} > //Link that doesn't connect
<img src={props.img} alt={props.name} />
</Link>
</div>
)
};
Above is your code which might look right but the is a slight bug here:
The bug is in the wrong way you are linking to path="/cardID/:id
What you are to do is in your Card child2 is:
const Card = (props) => {
return (
<div className={props.img ? "card" : "hide"}>
<Link to={`/cardID/${props.id}`} > //Removed **id=....**
<img src={props.img} alt={props.name} />
</Link>
</div>
)
};
This is what you have to understand that when you make a route like so path="/route/:id" the :id is just a placeholder waiting for you to place anything so id is commonly used so your code makes sense and mainly basically you want to route based on id but one could have written :cat for example but that is just a placeholder

React Nested Routing by `:id`

I am trying to create a blog style app with an "articles" page that has a list of posts which will render by postId. I have gotten the urls to generate and even my small <Post /> component to render, but when a post page renders the Articles content doesn't go away and the post content just renders below it. How do I fix this?
I have
App.js:
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route exact path="/articles">
<Articles />
</Route>
</Switch>
Articles.js:
import React from 'react';
import {
Link,
useRouteMatch,
Switch,
Route,
} from 'react-router-dom';
import Post from '../Components/Post';
import Banner from './Banner';
const Articles = () => {
let match = useRouteMatch();
return (
<div className='Articles'>
<Banner title='Articles'/>
<h3>Please select a topic.</h3>
<ul>
<li>
<Link to={`${match.url}/geojsons`}>Geojsons</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>
Props v. State
</Link>
</li>
</ul>
<Switch>
<Route path={`${match.url}/:postId`}>
<Post />
</Route>
</Switch>
</div>
)
}
export default Articles;
Post.js:
function Post() {
let { postId } = useParams();
return <h3>POST - Requested topic ID: {postId}</h3>;
}
export default Post;
Screen shot of problem page:
This screenshot shows the page after you click on an article link. The Post content is what I have in the dashed red box and everything above it should only be a part of the Articles page.
I know it is only a couple files but to make it easier to mess with I put a simplified version of the repo on github. No styling or anything just an html version of the problem.
Since you want Article and Posts pages to be separate, you need to decouple your post route from Article route and render it in App.js instead of Articles.js
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/articles/:postId">
<Post />
</Route>
<Route exact path="/articles">
<Articles />
</Route>
</Switch>
and in Article.js
const Articles = () => {
let match = useRouteMatch();
return (
<div className='Articles'>
<Banner title='Articles'/>
<h3>Please select a topic.</h3>
<ul>
<li>
<Link to={`${match.url}/geojsons`}>Geojsons</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>
Props v. State
</Link>
</li>
</ul>
</div>
)
}

react-router location.pathname such as /users/ that matches both /users/profiles and /users/details. /users/* if you may

I am using react-router for programatic navigation in my app. All is fine expect for this new feature I want to add, that requires conditional routing.
I need to render, for instance profileRoutes when location is /users/profile and somethingElse when location is /users/details for instance. The code below works fine for now as I only have profileRoutes built. But I consolidated the routes into one, and need /users/* or something to that effect, such that that location would match all routes related to /users/...
<Route
children={({ location }) => (
<div>
{
location.pathname === "/users/profiles" ?
<profileRoutes></profileRoutes> :
<otherComponent/>
}
</div>
)}
/>
My question: Is there a react-router way to achieve this? like location.pathname.startswith.... sort of thing?
For your requirements, please use the parameter exact.
To match either /users or /users/profiles or /users/what-ever:
<Route path="/users" component={Users} />
To match only /users
<Route exact path="/users" component={Users} />
In principle, let do as follows:
In the main component, use Route without exact to point to
the component Users
In component Users, use Route again to match
sub-components of Users
Here is the example:
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
export function RouterExample() {
return (
<Router>
<div>
<ul>
<li>Main Menu:</li>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/users">Users</Link>
</li>
</ul>
<hr />
<Route exact path="/" component={Home} />
<Route path="/users" component={Users} />
</div>
</Router>
);
}
function Home() {
return (
<div>
<h2>Welcome home</h2>
</div>
);
}
function Users({ match }) {
return (
<div>
<h2>Welcome to Users</h2>
<ul>
<li>Users menu:</li>
<li>
<Link to={`${match.url}/profiles`}>User Profiles</Link>
</li>
<li>
<Link to={`${match.url}/settings`}>User Settings</Link>
</li>
</ul>
<Route exact path={`${match.path}`} component={UserHome} />
<Route path={`${match.path}/profiles`} component={UserProfiles} />
<Route path={`${match.path}/settings`} component={UserSettings} />
<Route path={`${match.path}/:section`} component={UserFooter} />
</div>
);
}
function UserHome() {
return (
<div>
<h3>UserHome Component</h3>
</div>
);
}
function UserProfiles() {
return (
<div>
<h3>UserProfiles Component</h3>
</div>
);
}
function UserSettings() {
return (
<div>
<h3>UserSettings Component</h3>
</div>
);
}
function UserFooter({ match }) {
return (
<div>
<hr />
UserFooter Component is always visible under /users/*
<br />
You are now at
<br />
path: {match.path}
<br />
match params: {match.params.section}
</div>
);
}
Live demo at codesandbox
Thanks for pointing me in the correct direction, ie using match!
I didn't need to modify my routes though (I like to keep my components separate and just import instead. I do have an exact tag on the root component, /.
Here's what worked for me:
<Route
children={({ match }) => (
<div>
{
match.path == "/users" ?
<profileRoutes></profileRoutes> :
<otherComponent/>
}
</div>
)}
/>
Now when match.path == "/users" is true, all routes downstream ie /users/etc are rendered.
Hope this helps someone else!

passing a dynamic url with React

Thanks to everyone for your efforts to help me before at How to pass and retrieve data over the url in React I don't know why it wasn't working but I decided to simplify things and just pass a string instead of an object but it still isn't being read. Instead of having a dynamic url, it just passes the string ":i" or ":book.id" or whatever value I try to use in the Link tag.
App.js
<Router>
<div className="App">
<Header />
<Switch>
<Route path="/" component={Main} />
<Route path='/:i' component={Single} />
</Switch>
</div>
</Router>
Main.js
const Main = () => {
return (
<div id="main">
{data.map((book, i) => {
return (
<div key={i} className="squares">
<img
src={images[book.picture]}
className="covers"
alt="book cover"
/>
<h3>
///////////////////////!!! HERE !!!/////////////////////////////////////
**<Link to="/:i">{book.title}</Link>**
</h3>
Book.js
const Book = (props) => {
let id = useParams();
console.log("1", id); ////logs ':i'
You should not pass params in Link like this.
You pass parameter value, like id.
<Link to={`/${i}`}>
And then in route you receive it
<Switch>
<Route path="/:id" children={<Child />} />
</Switch>
Here is doc with examples

Resources