user1056585
user1056585

Reputation: 720

ReactJS router + component hierarchy when swapping out components with route changes

TLDR: I'm trying to figure out how to arrange nested routes and my components so that a component can be swapped out based on route.

In SUPER simple terms, I'm trying to build an application where teachers can see the classes they teach at colleges.

The routes of the application are:

  1. /dashboard: call backend to check if the teacher has a default college set on their account, if not then present a college picker dialog where the teacher can select a default college. Once there's a default college (say COLLEGE1), re-route to next route (next bullet point)
  2. /dashboard/college/COLLEGE1: fetch metadata of classes taught in college.
  3. /dashboard/college/COLLEGE1/class/CLASS1: show metadata of a single class within COLLEGE1. This route is accessed by clicking a class in bullet 2.

Here are rough mocks of what this interaction would look like when static (I've colored each component so it's easier for you to refer to them when responding):

Rough mocks of interaction

However, I am just not able to figure out the nested routes + component hierarchy structure that would get me this.

The hierarchy I have so far is:

<Home>
    <Header/>
        <!-- content in header -->
    </Header>
    <MainContent>
        <!-- Either loading, for e.g. to fetch permissions -->
        <Loading />

        <!-- OR display navigation + content -->
        <MainContentPage>
            <!-- show navigation pane on left, and then choose from report / T and Cs / Contact -->
            <Navigation>
                <CurrentCollegeInfo />
                <DashboardLink />
                <TermsAndConditionsLink />
                <ContactUsLink />
            </Navigation>

            <ReportPage>
                <!-- Either Loading -->
                <Loading />
                
                <!-- OR have user select default college -->
                <DefaultCollegePickerPopup />
            
                <!-- OR show college report or class details -->
                <CollegeReportPage />
                <ClassDetailsPage />    

                <!-- OR error pages: Not Found, 500, etc. -->
                <ErrorPage />
            </ReportPage>

            <TermsAndConditionsPage />
            <ContactUsPage />

        </MainContentPage>
    </MainContent>
</Home>

How do I insert route management here (I'm using react-router library at the moment btw) so that in the ReportPage component:

  1. either the route is /dashboard (when loading default college from backend or asking user to pick one)
  2. or it is /dashboard/college/COLLEGE1 and fetch college report
  3. or it is /dashboard/college/COLLEGE1/class/CLASS1 and fetch class details?

Or is this not possible and I should rather figure out another flow?

Upvotes: 0

Views: 170

Answers (1)

demitchell14
demitchell14

Reputation: 195

So if I understand correctly, you want to use the react-router to load different components based on which endpoint the user is on? This is 100% possible. You just pass the component you want to show for a specific route as a component property.

You can also use parameters in the paths, so in your example, you have /dashboard/COLLEGE1... I'm assuming you need that to be dynamic to allow for any college. This is done with placing parameters into the path like so... /dashboard/:somevariablename.

<Route
    // exact

    path={"/dashboard"}
    // path={"/dashboard/:collegeId"}
    // path={"/dashboard/:collegeId/classes/:classId"}

    component={ComponentToPass}
/>

If you make a Route for every possible component/page that the user can visit, and wrap it in a <Switch> component, it will show only one component. You can however skip the <Switch> and add multiple routes to an endpoint as well.

I'm assuming you'll need to use the collegeId and classId in the corresponding components. If you are using functional react, use const { VARNAME } = useParams() to retrieve the parameters you are using. If you are using class-based react, all you need to do is call this.props.match.VARNAME. -- Both are obviously used inside the component that you want to show/use.

So to change your code up a little bit (could be done in a dedicated routes component), heres a light example..

import {HashRouter, Switch, Route} from "react-router-dom"
import DefaultCollegePickerPopup from './wherever'
import CollegeReportPage from './wherever'
import ClassDetailsPage from './wherever'

function RouterComponent(props) {

    return (
        <HashRouter>
            <Switch>

                <Route 
                    exact 
                    path={"/dashboard"}
                    component={DefaultCollegePickerPopup} 
                />
                <Route 
                    exact 
                    path={"/dashboard/:collegeId"} 
                    component={CollegeReportPage}
                />
                <Route 
                    exact 
                    path={"/dashboard/:collegeId/class/:classId"} 
                    component={ClassDetailsPage} 
                />
                
            </Switch>
        </HashRouter>
    )
}
function CollegeReportPage(props) {
    const { collegeId } = useParams();

    return (
    <div>College report for {collegeId}</div>
    )
}

class CollegeReportPage extends React.Component {
    render() {
        const { collegeId } = this.props.match
        return (
            <div>College report for {collegeId}</div>
        )
    }
}

If you haven't already looked at this, I would. It gives a LOT of useful information.

https://reactrouter.com/web/guides/quick-start

Upvotes: 1

Related Questions