basically im rendering this react component:
<Grid>
<Him className="him"><Link to="/him">Him</Link></Him>
<Her className="her"><Link to="/her">Her</Link></Her>
</Grid>
essentially just 2 boxes with links to him and her.
I have this route that correctly renders my Categories when you click on him.
<Route
path="/him"
render={() => (
<Categories
products={products}
addToBasket={addToBasket}
/>
)}
/>
However it renders this component underneath the him/her components. It might sound silly but how do I get it to render them over the top or instead of it?
I could something where I set the state of the component to visible: false and toggle that but that seems a bit messy.
all the stuff in this tutorial: https://reacttraining.com/react-router/web/example/no-match, seems to have them routing via header that never disappears, whereas I want to click on links in the body of my application and then show different content. any ideas?
You have to wrap the Grid in a Route as well. You could do something like this
<Route path='/' exact component={LinkComponent} />
And somewhere else in your code:
const LinkComponent = () => (
<Grid>
<Him className="him"><Link to="/him">Him</Link></Him>
<Her className="her"><Link to="/her">Her</Link></Her>
</Grid>
);
This way, if you go to the home route, you see the Grid, and when you click on a Link, you go to corresponding route and the Grid will be hidden.
Ok you just wants to replace the entire content when click on /him or /her, so as Xander Berkein said you should render your links into a main component and then assign it to the / main route, y that way you need to use exact prop to just render that first path that matches to the URL, so
<Switch>
<Route exact path={‘/‘} component={<Links/>} />
<Route exact path={‘/him’} component={<HimComponent/> />
<Route exact path={‘/her’} component={<HerComponent /> />
</Switch>
I hope you find it useful.
Related
I am using React-Router-Dom to navigate between two javascript elements in a create-react-app dapp but when I use it loads the elements on top of the page and just adds the page to the end of the link (localhost/page).
My goal is to have the page reload to the new page on click of the link button with a new background and styling (already done for that page)
App.js Code
<Router>
<s.Screen>
<Navbar />
<Routes>
<Route path="/MyPandas" element={MyPandas} exact></Route>
</Routes>
/*
Rest of Code
*/
</Router>
My other page is just wrapped in a Fragment Component
<Fragment>
/*
Code
*/
</Fragment>
use exact in your Routes e.g : <Route path='/products' exact>
Assuming your links are working correctly, and it seems they are if the URL in the address bar updates to "/MyPandas".
The issue is that the element prop isn't passed a correct value. react-router-dom#6 Route component's element prop takes a ReactNode, a.k.a. JSX, not a reference to a React component. Pass <MyPandas /> instead of MyPandas.
<Route path="/MyPandas" element={<MyPandas />} />
Note: There's no need for the exact prop. Not only does it not exist in the RRDv6 Route component API, but all routes are now always exactly matched.
So I've been working on a project lately using React js (I thought it would be similar to React native), while I pretty much understand most of it as I previously worked with React native a lot. There are still some new things I'm learning for example the react-router-dom npm. So I understand the basics and how it works, but I'm trying to use parameters which change depending on the user (User ID).
The code below shows how I'm currently using my router. While going to home (/) and /user/:id works, I can't go to /user/:id/settings. If I try going to the settings it renders both the /user/:id page and below it renders settings page.
What I want to be able to do is if the user is in the user/:id page they can click a button which takes them to the user/:id/settings instead of the current issue where it renders the setting page below the user page.
App.jsx
export class App extends React.Component {
render() {
return (
<Router>
<Route exact path="/" component={Home} />
<Route path="/user/:id" component={User} />
<Route path="/user/:id/settings" component={Setting} />
</Router>
)
}
};
User.jsx
render() {
return (
<div>
{/* Cool information about the user */}
<div
className="optionContent"
onClick={() => {
let uri = `/user/${this.props.match.params.id}/settings`;
this.props.history.push(uri)
}}
>
Press me
</div>
</div>
);
}
Extra information:
I have tried using variable parameters for users but I wasn't able to full make those work as once the user enters /user/:id page the buttons update the url but not the parameters in this.
I need to have the ID within the url to fetch from the API and some other stuff
Variable url: /user/:id/:type?
This is because with React Router v5 which is currently the latest version as v6 is completed, the routes aren't exact by default which means that for each of the routes, if the current route starts with the route of a component, this component will be displayed.
For your example:
<Router>
<Route exact path="/" component={Home} />
<Route path="/user/:id" component={User} />
<Route path="/user/:id/settings" component={Setting} />
</Router>
If the current route is "/user/user1" then it only matches the User component.
If the current route is "/user/user1/settings/ then it matches User and Settings components so they will both be rendered as you are finding.
To fix it, simply use the exact keyword on the component with the fewer requirements.
<Router>
<Route exact path="/" component={Home} />
<Route exact path="/user/:id" component={User} />
<Route path="/user/:id/settings" component={Setting} />
</Router>
I am setting up a basic navbar, it just has some buttons, not any complex log or anything. When I have this navbar inside of the switch, no other componet loads, meaning I cannot wrap the navbar between certain components, when I have the navbar outside of the switch , then it works, and I can just check if props.match.location etc is "/" and not load it on homepage, so I found a workaround, but what could be causing this bug, or is it expected behavious, I suspect my wildroutes, but not 100% sure what .
Where I am using navbar
const App = () => {
return (
<div>
<Router>
<Switch>
<Route component={theNavbar} />
<Route exact path="/" component={Home} />
<Route exact path="/api/:city/electronics" component={Electronics} />
<Route exact path="/api/:city/labour" component={Labour} />
<Route exact path="/api/posts/item/:id" component={ItemDetails} />
<Route exact path="/create/:city/:category" component={CreatePost} />
</Switch>
</Router>
</div>
);
};
It's completely expected behavior, and caused by a couple of factors. First is the Switch, and the second is the match anything Route for the nav.
Switch
Renders the first child <Route> or <Redirect> that matches the
location.
All subsequent matches won't render at all.
Route path
Routes without a path always match.
<Route component={theNavbar} />
This route matches all locations and thus will always match. Being listed first within a Switch means it will always render.
The solution to always render some navigation component while still matching other routes is to move that component outside of the Switch but still within the Router.
This is expected behavior. Per the React Router documentation:
Routes without a path always match.
So your NavBar will always be matched in the <Switch> and none of the other components will render.
How to make nested routes???
I want initial route to be course/:course_id? after that, when i click on a node I want my url to become course/:course_id?/nodes/:node_id .
I use : "react-router-dom": "^4.2.2"
return (
<Router>
<div id="app-main">
<Header />
<Route path="/course/:course_id?" component = {Content}/>
<Route path="/course/:course_id?/nodes" component = {Content}/>
<Footer />
</div>
</Router>
);
When i click id redirects me to course/nodes and skips :course_id
return(
<div className="paragraph-text-child" onClick={() => this.props.select(chapter)} key={chapter.node_id} >
<Link to="nodes">{chapter.text}</Link>
{this.iterate(chapter.nodes)}
</div>
);
I think you have some concepts mixed up... Route is for handling received URLs, Link is for setting it.
Link does not know about Route, Route does not know about Link. Link sets the URL to what is specified in to. So if your current URL is /course, and to="nodes", the result is /course/nodes. If it was to="0/nodes", the result would be /courses/0/nodes.
Now if I understood correctly, you always want a number between "/courses" and "/nodes", correct?
This can be achieved with Redirect, which comes from react-router-dom too.
If you create the following Route:
<Route path="/courses" render={()=> <Redirect to="/courses/0"/>}/>
And rework the previous route so that course_id is NOT optional
<Route path="/course/:course_id" component={Content}/>
When you navigate to /courses, you will be silently redirected to courses/0. The result is that your Link component with to="nodes" will always redirect to courses/number/nodes - because effectively the courses/ location won't be reachable anymore. Every URL that would not contain a course_id, will be redirected to course_id = 0
Note that these 2 routes should be put in a Switch, and in the correct order, otherwise you will end up redirecting every time...
I have not tested this, but it should do the job:
...
<Header/>
<Switch>
<Route path="/course/:course_id" component={Content}/>
<Route path="/courses" render={()=> <Redirect to="/courses/0"/>}/>
</Switch>
<Footer/>
...
And this should handle /course/course_id
Now, if you want to nest a /course/:course_id/nodes/:node_id Route, that should go into the component rendered by the parent route.
Let's rework our parent Route into this:
<Route path="/course/:course_id" render={(props) => <Content ...props />}/>
What this does is, instead of just rendering the passed component, it renders the component and passed down Router props. Which means that the rendered component will be able to handle routes!
Now, in the Content component:
render() {
return <Route path="/course/:course_id?/nodes/:node_id?" component={NodeContent}/>
}
The last thing we need to do is change the to property of the Link component so that it will redirect to the target node:
<Link to={"nodes/" + chapter.node_id}/>
Does this make sense? I may have missed some gotchas in your code - the idea of what you want to achieve is in here, but you may have to adapt it a bit...
so heres the sample:
simple menu/header JSX:
<Menu fixed='top' inverted>
<Container>
<Menu.Item header>Simple Blog</Menu.Item>
<Menu.Item name='home' as={Link} to='/'
active={this.state.activeItem === 'home'}
onClick={this.handleItemClick}>Home</Menu.Item>
<Menu.Item name='create-p' as={Link} to='/create-post'
active={this.state.activeItem === 'create-p'}
onClick={this.handleItemClick}>Create post</Menu.Item>
</Container>
</Menu>
then I have basic index.js:
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<BrowserRouter>
<div>
<ApplicationMenu/>
<Container style={{marginTop: '5em'}}>
<Route exact path="/" component={Posts}/>
<Route exact path="/home" component={CreatePost}/>
</Container>
</div>
</BrowserRouter>
</Provider>
, document.querySelector('.start'));
It renders and looks fine. When I click one of menu items I can see the URL changing, but no action is taken besides that. Router does not render new component. If I select the changed URL and click enter, it renders the proper one, but it looks like it does not react on url changes provoked by semantic ui component.
For debug purposes I prototyped these menu items just using clean html and css (pure sui, not react one) and it worked.
Did anyone have have similar problems and managed to figure it out?
Thanks for any answer.
This is a common problem to react-router-dom.
React works the way that it rerenders everytime either:
the properties of a component change
the internal state changes
If you change the URL of the page, you do not trigger a rerender of that component. Therefore, your index.js won't be rerendered.
A simple solution to this problem is to wrap your Component with a withRouter.
So your new index should look like this:
import { withRouter } from 'react-router-dom';
ReactDOM.render(withRouter(
<Provider store={createStoreWithMiddleware(reducers)}>
<BrowserRouter>
<div>
<ApplicationMenu/>
<Container style={{marginTop: '5em'}}>
<Route exact path="/" component={Posts}/>
<Route exact path="/home" component={CreatePost}/>
</Container>
</div>
</BrowserRouter>
</Provider>)
, document.querySelector('.start'));
Now when the URL changes, the higher order component "withRouter" notices it and rerenders the component in it, so your correct component will be rendered.
As documented here: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md
If you want to know more about the problem, read this GitHub issue: https://github.com/ReactTraining/react-router/issues/5037
Your Route path don't match your Item Link to.
Try changing your routes to:
<Switch>
<Redirect exact path="/" to="/home">
<Route exact path="/home/" component={Posts}/>
<Route exact path="/create-post/" component={CreatePost}/>
</Switch>
BTW: Take a look at react-router's <NavLink> to use instead of <Link> for your Navbar items.