Routing pages into components: React - reactjs

I have 3 components: Header.js, Main.js, and Footer.js, and App.js is like
const App = () => {
<Header/>
<Main/>
<Footer/>
}
In the Header.js I have links like About and Projects. I would like to be able when I click About in the header for example to display the page About.js in Main.js, and when I click Projects to display the page Projects.js in the Main.js component. I tried to use Routing in the Main.js component like
const Main = () => {
<Router>
<Switch>
<Route exact path='/' component={About.js} />
<Route exact path='/projects' component={Projects.js} />
</Switch>
</Router>
}
but it wouldn't allow me, saying that I cannot use Link outside a router, where I use Link in the Header.js. How can I achieve this?
The Header.js is the following
const Header = () => {
return (
<div>
<ul>
<li>
<Link to="/">
About
</Link>
</li>
<li>
<Link to="/projects">
Projects
</Link>
</li>
</ul>
</div>
)
}

You simply need to make sure your Router component surrounds any components doing routing. For simplicity, here’s the router surrounding your whole app at the App level.
const App = () => {
<Router>
<Header/>
<Main/>
<Footer/>
</Router>
}
Edit: make sure you’re passing your components correctly to the Routes:
const Main = () => {
<Switch>
<Route exact path='/' component={About} />
<Route exact path='/projects' component={Projects} />
</Switch>
}

Related

React Router V5 How to have links to nested and parent router? Adding Redux messes with Routing

I have a page which uses React Router V5. There is a general section and there is a section specifically for user profiles. As I have a different page structure there, I used nested routes for the account section. The SideBar is what the name implies and contains buttons which can be used to navigate the account pages /account/profile, /account/settings, as well as navigate to pages outside the nested switch - namely /help.
The App used to be structured roughly like this:
// in index.js
const appDiv = document.getElementById("app")
render(<App />, appDiv)
// in App.js
const App = () => {
return (
<Router>
<div className={styles.pageContainer}>
<Header />
<Switch>
<Route exact path='/' component={() => <HomePage link='about' />} />
<Route path='/about' component={AboutPage} />
<Route path='/help' component={HelpPage} />
<Route path='/log-in' component={LoginPage} />
<Route path='/sign-up/:signupType' component={SignUpPage} />
<Route path='/account' component={AccountRouter} />
</Switch>
<Footer />
</div>
</Router>
}
// in AccountRouter.js
const AccountRouter = () => {
return (
<div className={styles.container}>
<SideBar />
<Switch>
<Route path='/account/settings' component={AccountSettingsPage} />
<Route path='/account/profile' component={ProfileSettingsPage} />
<Route exact path='/account' component={ProfileSettingsPage} />
</Switch>
</div>
);
};
// in SideBar.js
const SideBar = () => {
const history = useHistory();
return (
<div>
<button onClick={() => history.push('/account/profile')}>Go to Account Profile</button>
<button onClick={() => history.push('/account/settings')}>Go to Account Settings</button>
<button onClick={() => history.push('/help')}>Go to Help Page</button>
</div>
)
}
Now it is structured like this:
// in index.js
const appDiv = document.getElementById("app")
render(
<Provider store={store}>
<App />
</Provider>
, appDiv)
// in App.js
// This looks the same
// in AccountRouter.js
// This now has Route protection
const AccountRouter = () => {
const accountData = useSelector((state) => state.account);
return (
<div className={styles.container}>
{!accountData.isLoggedIn ? <Redirect to='/log-in' /> : null}
<SideBar />
<Switch>
<Route path='/account/settings' component={AccountSettingsPage} />
<Route path='/account/profile' component={ProfileSettingsPage} />
<Route exact path='/account' component={ProfileSettingsPage} />
</Switch>
</div>
);
};
// in SideBar.js
// This looks the same.
Before I added Redux, the Sidebar was properly redirecting.
After Redux, I have the following behaviour:
When the SideBar is outside of the Switch, you can properly navigate to the Help page, but the components don't render, when I try to navigate to the pages inside the AccountRouter Switch. When I move the SideBar into the Switch, the links to the pages inside this switch start working again, but the /help link stops working.
Is there a way of having links to both inside and outside of this Switch in the same SideBar? How could Redux have affected the Router?

how to use router inside a routed component

My App.js:
<Router>
<Header/>
<Switch>
<Route exact path="/" component={HomeScreen} />
<Route exact path="/screenOne" component={OneScreen} />
<Route exact path="/screenTwo" component={TwoScreen} />
</Switch>
</Router>
The <Header /> has three links to the respective components viz. HomeScreen, OneScreen, TwoScreen.
I want my <TwoScreen /> to be exactly like this baseComponent(i.e App.js) where I have some links and when I click those links, the components corresponding to the link/path gets rendered.
What is the best way to approach this?
there is an example on the react-router site that meets your need, under nesting, you can check it out https://reactrouter.com/web/example/nesting (for just web)
But for me, I simply declare them all in one place/component, especially on react-router-native, if you're doing react-native.
below is the example from their website for web
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useParams,
useRouteMatch
} from "react-router-dom";
// Since routes are regular React components, they
// may be rendered anywhere in the app, including in
// child elements.
//
// This helps when it's time to code-split your app
// into multiple bundles because code-splitting a
// React Router app is the same as code-splitting
// any other React app.
export default function NestingExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>
<hr />
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/topics">
<Topics />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return (
<div>
<h2>Home</h2>
</div>
);
}
function Topics() {
// The `path` lets us build <Route> paths that are
// relative to the parent route, while the `url` lets
// us build relative links.
let { path, url } = useRouteMatch();
return (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${url}/rendering`}>Rendering with React</Link>
</li>
<li>
<Link to={`${url}/components`}>Components</Link>
</li>
<li>
<Link to={`${url}/props-v-state`}>Props v. State</Link>
</li>
</ul>
<Switch>
<Route exact path={path}>
<h3>Please select a topic.</h3>
</Route>
<Route path={`${path}/:topicId`}>
<Topic />
</Route>
</Switch>
</div>
);
}
function Topic() {
// The <Route> that rendered this component has a
// path of `/topics/:topicId`. The `:topicId` portion
// of the URL indicates a placeholder that we can
// get from `useParams()`.
let { topicId } = useParams();
return (
<div>
<h3>{topicId}</h3>
</div>
);
}

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>
)
}

How to reload component when URL is changed in react router

In my React Application I need to reload the component when it comes to the path path="/". I know react-router helps us reload easily the current component but I really need this in my application for some styling purpose. In my application I have two paths:
<Route path="/" component={newRoute}/>
and <Route path="/gallery" component={GalleryImages}/>. So, whenever I move from GalleryImages to newRoute I need to reload the newRoute components otherwise the styles are not working. What is the way around here? Here's myApp.js now:
const newRoute = () => {
return (
<div id="colorlib-page">
<div id="container-wrap">
<div id="colorlib-main">
<Introduction/>
<About/>
<Projects/>
<Timeline/>
<Blog/>
</div>
</div>
</div>
)
}
class App extends Component {
render() {
return (
<BrowserRouter>
<div>
<Sidebar/>
<Switch>
<Route path="/" component={newRoute} exact/>
<Route path="/gallery" component={GalleryImages} exact/>
<Route component={Error}/>
</Switch>
</div>
</BrowserRouter>
);
}
}
export default App;
Try to use class component instead of functional component

How to navigate on a page without reloading the page

I have navigation in react and want to redirect to the listing page on click.using this right now which is loading the page
This is my Header.js file
return (
<Link to="/allusers">All Users</Link>
);
This is my App.js file
I imported this
import UsersList from './user/UsersList'; //then i defined
class App extends Component {
render () {
return (
<BrowserRouter>
<div>
<Header />
<Switch>
<Route exact path='/userlist' component={UsersList} />
</Switch>
</div>
</BrowserRouter>
)
}
}
You can check react-router or #reach/router
For example, in #reach/router, you can use the provided Link component to create the same anchor as in your example:
<Link to="/userlist">All Users</Link>
And create a router with all your routes:
<Router primary={false}>
<Home path="/" />
<AllUsers path="/allusers" />
<NotFound default />
</Router>
https://github.com/reach/router
You can play around with this example: https://reach.tech/router/tutorial/04-router
Same thing can be done with react-router.
This achieved through a client side routing: manipulation of the history object of the browser through client side
This is an example rendering a specific component for specific route
import { BrowserRouter, Route, Link, Switch } from "react-router-dom"
<BrowserRouter>
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/allusers" component={AllUsers} />
<Route component={NotFoundPage} />
</Switch>
</BrowserRouter>
// then just pair it up with a navigation bar
<Link to="/">All Users</Link>
<Link to="/allusers">All Users</Link>
These components tied up to a route has access to history object as prop where you can call history.push('/allusers') for other use cases
reference:
https://reacttraining.com/react-router/web/guides/quick-start
You can do that as follows:
goToUserList = () => {
this.props.history.push('/userlist')
}
...
return(
<button onClick={this.goToUserList}>Go User List</button>
)
Hope it helps.

Resources