Search code examples
reactjsreact-routerurl-parametersdynamic-content

React - display specific content based on URL using useLocation


Trying to teach myself react and stuck on one part... I can't seem to get page specific content to display based on URL using useLocation() -- HELP!

App.js - router displays page on click, yay!

    <Router>
        <Routes>
            <Route exact path="/" element={<Home />} />
            <Route path="/project/projectOne" element={<Project />} />
            <Route path="/project/projectTwo" element={<Project />} />
        </Routes>
    </Router>

Project.js - Project template serves up the components as expected

const Project = () => {
return (
    <div className='content-wrapper'>
        <Scroll />
        <ProjectIntro />
        <ProjectContent />
        <ProjectGrid />
        <Contact />
    </div>
); }; export default Project;

ProjectIntro.js - A component trying to serve up the content -- this is where I'm stuck, useLocation() see's the path, but I can't figure out how to show the "projectIntroDetails" based on that path.

const projectOne = () => {
  <h1 className='project-intro-heading'>Title Here</h1>,
  <figure className='project-intro-image'>
    <img src={projectImage} alt='placeholder'/>
  </figure> 
}

const projectTwo = () => {
    <h1 className='project-intro-heading'>Title Here</h1>,
    <figure className='project-intro-image'>
        <img src={projectTwoImage} alt='placeholder' />
    </figure>
}


const projectIntroDetails = {
    projectOne: {
        component: <projectOne />
    },
    projectTwo: {
        component: <projectTwo />
    }
}

const ProjectIntro = () => {
    const projectPath = useLocation();
    console.log(projectPath);

    // this is where I need help
    // how do I turn the path into seeing details to render the correct content?
    const projectIntroDetail = projectIntroDetails[projectPath.pathname.split("/project/")];

    return (
        <div className='project-intro'>
            {projectIntroDetail}
        </div>
    );

}; export default ProjectIntro;

Solution

  • You can use a component with a switch statement to determine which child component to render. This method allows you to pass any additional props to the child components.

    If you don't need the <div className='project-intro'> element, you could also render the switch directly inside your ProjectIntro component.

    const ProjectOne = () => {
      <h1 className='project-intro-heading'>Title Here</h1>,
      <figure className='project-intro-image'>
        <img src={projectImage} alt='placeholder'/>
      </figure> 
    }
    
    const ProjectTwo = () => {
        <h1 className='project-intro-heading'>Title Here</h1>,
        <figure className='project-intro-image'>
            <img src={projectTwoImage} alt='placeholder' />
        </figure>
    }
    
    const ProjectIntros = ({ slug, ...props }) => {
        switch(slug) {
            case 'projectOne':
                return <ProjectOne {...props} />;
            case 'projectTwo':
                return <ProjectTwo {...props} />;
            default:
                return null;
        }
    }
    
    const ProjectIntro = () => {
        const projectPath = useLocation();
        console.log(projectPath);
    
        return (
            <div className='project-intro'>
                <ProjectIntros slug={projectPath.pathname.split("/")[2]} />
            </div>
        );
    
    }; export default ProjectIntro;