React Router v4 - page composition - javascript

Here is what I want to implement:
In the case of /event and /customercenter, the header and footer are shown and only the contents of the main tag are changed.
On the other hand, the /login and /register pages do not show the header and footer.
First of all, my website's page composition is as follows.
/
-- /event
-- /customercenter
/login
/register
I do not seem to be solving the problem because I think I am misunderstanding the matching.
When one enters the /event page,
/ Was basically a match, so I thought that the component rendered in / would be drawn.
So /, /login and /register are branched using switch and exact, and the pages to be rendered under / are simply configured in the form of <Route path = {...} component = {...}.
To implement this, I have tried to implement it by referring to other articles in the stack overflow, but for some reason the router can not catch components from /register and /login(instead it returns null).
In a nutshell:
expected result : no header and footer on /login and /register
current result : /login and /register with no matching compoennt with header and footer.
following is my simplified code:
index.js
ReactDOM.render(
<Router>
<App />
</Router>
, document.getElementById('root'));
App.js
class App extends Component {
render() {
return (
<Switch>
<Route path="/" component={Home}/>
<Route exact path="/login" component={Login} />
<Route exact path="/register" component={Register} />
</Switch>
);
}
}
To make /login and /register avoid matching / I used exact. But it didn't match anything.
Home.js
class Home extends Component {
render() {
return (
<div className="App">
<MainHeader />
<AwesomeRouter />
<Footer/>
</div>
);
}
}
router.js
class AwesomeRouter extends Component {
render() {
return (
<div>
<Route path='/event' component={Event}/>
<Route path='/customercenter' component={CustomerCenter}/>
</div>
);
}
}

You can move the '/' path to the bottom of the list and remove exact from the routes.
Therefore, if '/login' and '/register' don't match, then '/' will match:
<Switch>
<Route path="/login" component={Login} />
<Route path="/register" component={Register} />
<Route path="/" component={Home}/>
</Switch>
Your '/event' and '/customercenter' routes will then also match '/' as it is not set to an exact match.

Related

Browserrouting only running when displaying App

I build a website in react with Browserrouting and have the following code & issue
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/" element={<App/>}>
<Route path="/home" element={<Homepage />} />
The Problem I have is when i run the App it opens the "App" and not the actual Homepage.
I tried to fix it by changing change the App to Homepage but it is not working.
In my understanding / needs to be there so the App displays in any other Path and is functioning.
Can some explain me, how i can make the path / still the Homepage without having to type /home to get there?
Thank you !
It appears you are rendering the Homepage in a nested route that is rendering App. In this configuration <Route path="/" element={<App />}> is what is called a Layout Route. App will be rendered when the path is exactly "/" and should render an Outlet component for the nested routes to render their content to.
An issue I see here, and you should have been seeing a react-router-dom invariant error regarding nesting an absolute path within a route rendering on an absolute path. In other words, "/home" is an absolute path and can't be nested under the absolute path "/"; it's not reachable.
If App really is a layout route and you always want it to render then you could remove the path prop from the parent route rendering App, and move Homepage to "/".
<BrowserRouter>
<Routes>
<Route element={<App />}>
<Route path="/" element={<Homepage />} />
</Route>
</Routes>
</BowserRouter>
or convert Homepage into an index route and leave the "/" path on the parent layout route so the relative routing can still work properly and Homepage is rendered on "/".
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
<Route index element={<Homepage />} />
</Route>
</Routes>
</BowserRouter>
I should point out that this is a slightly abnormal configuration. Typically the App component would render the Routes and Route components instead of an Outlet and it's assumed to all render on "/" by default. The Homepage component would then be rendered on path="/".
Example:
<BrowserRouter>
<App />
</BowserRouter>
...
const App = () => {
.... app logic ....
return (
<Routes>
<Route path="/" element={<Homepage />} />
</Routes>
);
};
There is OFC, the chance here that you didn't intend to nest these routes and want them to be matched and rendered independently. In this case the solution is to just unnest the Homepage route and continue using absolute paths for the root routes.
Example:
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path="/home" element={<Homepage />} />
</Routes>
</BowserRouter>
I found the issue
I had to
<Route path="" element={<App/>}>
<Route path="/" element={<Homepage />} />
Delete the Path / in App and only add Path / in Homepage.
It works now

React Router DOM is rendering 2 components

This is my router structure:
<Router>
<main className="py-3">
<Switch>
<Container>
<Route exact path="/admin" component={AdminScreen}></Route>
<Route path="/:campaignId" component={CampaignScreen}></Route>
<Route path="/" component={HomeScreen} exact></Route>
</Container>
</Switch>
</main>
</Router>
For "some" reason, when I go to /admin i also get the CampaignScreen rendered.
I added the <Switch> as you can see, but it does not seem to help.
Where lies the problem?
Since admin can theoretically also be a campaignId react router thinks it matches both routes, and you have the <Container> element directly inside the Switch it still renders both, the solution is to have your routes directly in the Switch

React Router: Routes within routes

I am building a React app that has a static marketing site and a dynamic app. I am using a combination of React Router and hooks to separate the two and ensure proper routing throughout.
To begin with, I want users who are logged in to be taken directly to the app when they hit the root ("/") and to the static/marketing site when not logged in. The main marketing site home page has a nav bar that allows users to access other routes such as "/about", whereas the app has a separate nav bar for app navigation.
The problem is, while the authentication based routing for the root route seems to be working, and I can navigate to other routes specified in my top-level file, the routes that are included within my static/marketing site are not accessible.
Top-level/index.js
const routing = (
<Provider store={store}>
<Router>
<NavWrapper />
{/* <Switch> */}
<Route exact path="/" component={AuthWrapper} />
<Route path="/signup" component={SignUp} />
<Route path="/login" component={Login} />
{/* </Switch> */}
</Router>
</Provider>
)
ReactDOM.render(routing, document.getElementById('root'));
AuthWrapper.js (here useAuth() is a React hook that evaluates global Redux isAuthenticated state)
const AuthWrapper = (props) => {
return useAuth() ? <App /> : <Website />
}
export default AuthWrapper;
website/index.js
export const Website = () => {
return (
<>
{/* <SiteNav /> */}
<Switch>
<Route exact path="/" component={LandingPage} />
<Route path="/about" component={AboutPage} />
<Route path="/how-it-works" component={HowItWorksPage} />
<Route path="/plans" component={PlansPage} />
<Route path="/press" component={PressPage} />
<Route path="/faq" component={FAQPage} />
<Route path="/legal" component={LegalPage} />
<Route path="/for-dieticians" component={DietitiansPage} />
<Route path="/for-trainers" component={PTsPage} />
</Switch>
</>
)
};
In my app, when I enter localhost:3000/ (unauthenticated) I am correctly taken to my home/landing page. However, if I try to use the navigation (or type in any subroutes) to access "/about" for example, I get a blank screen (other than the nav bar). In the React dev tools, the component isn't even rendering.
I think this is the issue:
<Route exact path="/" component={AuthWrapper} />
You want Authwrapper to be shown for about as well, right? But the above only matches "/" exactly.
You should enable the switch statement, but move the AuthWrapper Route to the bottom and then let it have this path: "/:rest*" (maybe "/*" works too, haven't used react-router in a while).
That way, it will use the Route if the first 2 don't match.

Redirect all routes in react router

I have a React/Redux app and if a user hasn't finished the signup process if they log in again I want them to be redirected to the signup route for the step they are on no matter what route they try to go to. What's the best way for me to do this without having to make a custom route for every single one of my routes with that logic inside? Here is my basic router:
render() {
return (
<Router history={history}>
<Switch>
<HomeRoute exact path="/" publicComp={Start} privateComp={Rooms}/>
<Route path="/login" component={Login}/>
<Route path="/signup" component={SignUpMain}/>
</Switch>
</Router>
);
}
Ideally, something where I can just say "on all of these routes if signup isn't complete redirect to /signup". Is there a way to do this?
One way would be to replace your Route components with a higher order component that redirects to signup.
const RedirectRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props =>
<Redirect
to="/signup"
/>
}
/>
);
If you add the higher order components to the bottom of the file with your Router above then you can just replace the Route components like so...
render() {
return (
<Router history={history}>
<Switch>
<RedirectRoute exact path="/" render={() => <HomeRoute exact path="/" publicComp={Start} privateComp={Rooms}/>}/>
<RedirectRoute path="/login" component={Login}/>
<Route path="/signup" component={SignUpMain}/>
</Switch>
</Router>
);
}
If you want to keep the higher order component in a seperate file then just import it like you would any other component.

Keep navigation bar on route switch

I have a problem with my react components.
Basically my interface should be an SPA, built with ReactJS.
During the implementation of the authentication with auth0-js I also implemented some routes.
The layout looks like this:
Whenever I click now on the "Recipes" link, it should redirect to the route "/recipes".
However, when I implement the route with <Route path="/recipes" component={Recipes} /> it only renders what is actually returned in the Recipes component. I know that this is correct from what react does.
Now, I want to keep the navigation bar but only want to exchange the component below, so I want to change what is below the navigation bar like I did in App.js.
How can I achieve this? Is something about the routes, or components not correct?
I do not want to re-render always everything. I also want to keep the style of the whole page. Is there a way to do this?
The whole code can be found here.
I agree with Jyutzio in that you need to move the Navigation component above the child routes to only change to content of the child routes.
In order to have the Navigation bar update with logged in / logged out state you may want to consider implementing redux. I have a project with nearly the exact requirements as yours - a navigation header that is static.
In my header I have import { connect } from 'react-redux';
At the bottom of the component I use connect before exporting:
function mapStateToProps(state) {
return { authenticated: state.auth.authenticated };
}
Header = connect(mapStateToProps)(Header);
export default Header;
Then this allows me to check the "authenticated" piece of state and render accordingly.
renderLogoutButton() {
if(this.props.authenticated) {
return(
<li><a onClick={...}>Logout</a></li>
);
} else {
return(
<li><a onClick={...}>Login</a></li>
);
}
}
You will need to setup a reducer, but there are many resources explaining redux setup.
The router (simplified) I have set up as follows:
import Admin from './index';
...
<BrowserRouter>
<Switch>
<Route exact path="/login" component={Login} />
<Route path="/" component={Admin} />
</Switch>
</BrowserRouter>
index:
import AdminRouter from './admin/admin_router';
...
<div>
<Menu />
<div>
<AdminRouter />
</div>
</div>
admin_router:
<div>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/details" component={AdminDetails} />
<Route component={PageNotFound} />
</Switch>
</div>
If you place your Navigation component above the switch, it will solve your problem.
const Routes = () => (
<Router history={history} component={Home}>
<Route component={Navigation}/>
<Switch>
<Route exact path="/" render={props => <Home auth={auth} {...props} />} />
<Route path="/home" render={props => <Home auth={auth} {...props} />} />
<Route
path="/callback"
render={props => {
handleAuthentication(props);
return <Callback {...props} />;
}}
/>
<Route component={NotFound} />
</Switch>
</Router>
);

Categories