Reputation: 111
I am looking to break apart my routing file into components so instead of
<BrowserRouter basename="/recruiter" >
<div>
<Nav />
<Switch>
/* HOMEPAGE ROUTES */
<Route exact path="/" component={Home} />
<Route exact path="/how-and-why" component={Pdf} />
<Route path="/sign-in" component={SignIn} />
<Route path="/investor-sign-in" component={SignIn} />
<Route exact path="/sign-in-error" component={SignInError} />
/* ADMIN ROUTES */
{this.props.AdminUser ?
<Route exact path="/welcome" component={LandingPage} />
<Route exact path="/companies" component={CompaniesTable} />
<Route exact path="/:companyId/edit-success" component={EditSuccess} />
<Route exact path="/:companyId" component={SingleCompanyTable} />
<Route exact path="/:companyId/:formId" component={SingleCompanyEdit} />
...10+ more Admin routes
: <Redirect to="/" />
}
/*USER ROUTES */
{this.props.regularUser ?
...additoinal User routes
: null
}
</Switch>
</div>
</BrowserRouter>
It is
<BrowserRouter basename="/recruiter" >
<div>
<Nav />
<Switch>
<Homepage Routes />
<AdminRoutes adminUser={this.props.adminUser} />
<UserRoutes regularUser={this.props.regularUser} />
//catch all
<Route component={NotFound} />
</Switch>
</BrowserRouter>
With each Route component (such as AdminRoutes) looking like
export const AdminRoutes = (props) => {
return props.adminUser ?
<div>
<Route exact path="/welcome" component={LandingPage} />
<Route exact path="/companies" component={CompaniesTable} />
<Route exact path="/:companyId/edit-success" component={EditSuccess} />
<Route exact path="/:companyId" component={SingleCompanyTable} />
<Route exact path="/:companyId/:formId" component={SingleCompanyEdit} />
...10+ more routes
</div>
: <Redirect to="/" />
In my understanding it should be the same render between the two options with the exception of the surrounding divs in the child component, but what happens is I can reach the routes in the first component, in this example HomepageRoutes, but none of the routes in AdminRoutes, UserRoutes etc.
I have had this previously working by wrapping sub components in switches, but then the catch all route/component (which is my 404 not found) are displayed all the time because of the contextual location change between the outer and inner switches.
I have read quite a bit on nested routes, but as far as I understand that involves wrapping the sub routes in another Route and the subroutes share the main route in their path
ie
const subRoute = () => {
return (
<Route path="/admin >
/* this should work? */
<Route path=/admin/:profile component={AdminProfile} />
/*doesn't work? */
<Route path="/add-company" component={AddCompany} />
</Route>
)
}
I would like to avoid this if possible so I don't have to re-write all my routes that I'd like to 'component-ize'
Pertinent package.json info:
"react": "^16.4.2",
"react-bootstrap": "^0.32.1",
"react-dom": "^16.4.2",
"react-loadable": "^5.4.0",
"react-redux": "^5.0.6",
"react-router-bootstrap": "^0.24.4",
"react-router-dom": "^4.3.1",
"react-test-renderer": "^16.4.2",
"redux": "^3.7.2",
"redux-form": "^7.3.0",
"redux-thunk": "^2.2.0"
Thank you in advance for your time and please let me know what other information to provide.
Upvotes: 1
Views: 2328
Reputation: 15652
You need to wrap your top-level route controller components (HomepageRoutes
, AdminRoutes
, etc.) in Route
components with path
attributes in the top-level switch.
Also note that Switch
matches the first Route
that matches a path (see docs), so if your first Route
has the path '/'
without the exact
attribute, it will always match so you won't get to any other Route
. To handle this, you can put your Route
for HomepageRoutes
at the end of the Switch
(but before NotFound
).
So your BaseRouter
should look like this:
<BrowserRouter basename="/recruiter" >
<div>
<Nav />
<Switch>
<Route path='/admin' render={ () => <AdminRoutes adminUser={this.props.adminUser}/> }/>
<Route path='/users' render={ () => <UserRoutes regularUser={this.props.regularUser}/> }/>
<Route path='/' component={ HomepageRoutes } />
{/* catch all */}
<Route component={NotFound} />
</Switch>
Note that any nested Route
components need to include the full path. So the paths of the Route
s nested within, say, AdminRoutes
will need to begin with '/admin/'
. From the documentation:
As soon as the app location matches the route’s path, your component will be rendered.
And I don't believe a Route
or Switch
knows whether or not it is nested.
For example if you have the location '/admin/welcome'
but your Admin LandingPage
only has path='/welcome'
, the path
and app location do not match and the LandingPage
component will not match. Instead the path
should be '/admin/welcome'
.
Edit for updated syntax:
Instead of using the render
(or component
) prop on the <Route>
component, you can pass as children, which I find to be easier syntax to read and work with.
<BrowserRouter basename="/recruiter" >
<div>
<Nav />
<Switch>
<Route path='/admin'>
<AdminRoutes adminUser={this.props.adminUser}/>
</Route>
<Route path='/users'>
<UserRoutes regularUser={this.props.regularUser}/>
</Route>
<Route path='/'>
<HomepageRoutes/>
</Route>
{/* catch all */}
<Route>
<NotFound/>
</Route>
</Switch>
Upvotes: 1