Home > Net >  Navigate to a page in a sub folder on item click in React JS
Navigate to a page in a sub folder on item click in React JS

Time:12-03

I'm very new to React JS but watched a few video tutorials on how to build my own portfolio. I want to map my portfolio items which contain an image, title, description, role and link. I managed to map everything except for the link to the detailed page of the respective portfolio item.

Could anyone please help me understand what I'm doing wrong and how to solve it please?

This is my folder structure:

src => pages where the main pages retain and src => pages => case-studies where the detailed pages of my portfolio items retain.

enter image description here

Here's what I got to so far:

Work.jsx in the src => pages folder

import React, { useEffect, useState } from "react";
import Loader from "./Loader";
import "./Work.css";
import WorkCard from "./WorkCard";
import WorkData from "./WorkData";

const Work = () => {
  return (
    <div className="work">
      <section className="work-section">
        <div className="card">
          <h1 className="underline">My portfolio</h1>
          <p>Here are the case studies of my projects...</p>

          <div className="grid-layout grid-2">
            {
              WorkData.map((val, index) => {
                return (
                  <WorkCard
                    key={index}
                    url={val.url}
                    image={val.image}
                    name={val.name}
                    description={val.description}
                    role={val.role} />
                 );
              })
            }
          </div>
        </div>
      </section>
    </div>
  );
}

export default Work;

WorkCard.jsx in the src => pages folder

import React from "react";
import { NavLink } from "react-router-dom";

const WorkCard = (props) => {
  return (
    <NavLink to={props.url} className="tile-card">
      <img src={props.image} alt={props.name} />
      <div className="details">
        <h2>{props.name}</h2>
        <p className="description" title={props.description}>{props.description}</p>
        <h4 className="role" title={props.role}>Role: {props.role}</h4>
      </div>
    </NavLink>
  );
}

export default WorkCard;

WorkData.jsx in the src => pages folder

import EcoPizza from "../assets/project-icons/ecoPizza.webp";
import Squared from "../assets/project-icons/Squared.webp";
import { EcoPizzaCaseStudy, SquaredCaseStudy } from "./case-studies";

const WorkData = [
  {
    "image": EcoPizza,
    "name": "The UX portfolio item name",
    "description": "This is description part",
    "role": "My role in that project",
    "url": EcoPizzaCaseStudy
  },
  {
    "image": Squared,
    "name": "The UX portfolio item name",
    "description": "This is description part",
    "role": "My role in that project",
    "url": SquaredCaseStudy
  }
];

export default WorkData;

index.js in the src => pages => case-studies folder

export { default as EcoPizzaCaseStudy } from "./eco-pizza/EcoPizzaCaseStudy";
export { default as SquaredCaseStudy } from "./squared/SquaredCaseStudy";

App.js

import React from "react";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import { Navigation } from "./components/Navigation";
import { Home, About, Work, Contact, PageNotFound, UnderConstruction } from "./pages";
import { Footer } from "./components/Footer";

function App() {
  return (
    <div className="App">
      <Router>
        <Navigation />
        <main>
          <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/about" element={<About />} />
            <Route path="/work" element={<Work />} />
            <Route path="/under-construction" element={<UnderConstruction />} />
            <Route path="/contact" element={<Contact />} />
            <Route path='*' element={<PageNotFound />}/>
          </Routes>
        </main>
        <Footer />
      </Router>
    </div>
  );
}

export default App;

CodePudding user response:

you are missing whole concept of routing. You can't just use item as a link to it. For that, we use Routes and then use url by Route defined accordingly.

So you need to fill up your Routes with missing items in App.js:

import React from "react";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import { Navigation } from "./components/Navigation";
import { Home, About, Work, Contact, PageNotFound, UnderConstruction } from "./pages";
import { Footer } from "./components/Footer";
//import required components
import { EcoPizzaCaseStudy, SquaredCaseStudy } from "./case-studies";

function App() {
  return (
    <div className="App">
      <Router>
        <Navigation />
        <main>
          <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/about" element={<About />} />
            <Route path="/work" element={<Work />} />
            <Route path="/under-construction" element={<UnderConstruction />} />
            <Route path="/contact" element={<Contact />} />
            // Add your routes
            <Route path="/eco-pizza-case-study" element={<EcoPizzaCaseStudy/>} />
            <Route path="/squared-case-study" element={<SquaredCaseStudy/>} />
            <Route path='*' element={<PageNotFound />}/>
          </Routes>
        </main>
        <Footer />
      </Router>
    </div>
  );
}

export default App;

And then for url use that defined path.

Instead "url": SquaredCaseStudy just do "url": "/squared-case-study"

Any path you choose will work as long as it is unique. You can make it /study/squared or any other, but you need to define it in App.js to use it

CodePudding user response:

I think you need to know Project structure

And also you need to name WorkData.jsx if you are going to expert just object data instead of JSX component. Just name it WorkData.js etc.

CodePudding user response:

So if I'm correct in understanding your issue, it is that you click the link and then navigate to "/work/EcoPizzaCaseStudy", for example, and then the PageNotFound component is rendered, or there is some error.

The code is currently attempting to use an imported React component as the link target.

import EcoPizza from "../assets/project-icons/ecoPizza.webp";
import Squared from "../assets/project-icons/Squared.webp";
import { EcoPizzaCaseStudy, SquaredCaseStudy } from "./case-studies";

const WorkData = [
  {
    "image": EcoPizza,
    "name": "The UX portfolio item name",
    "description": "This is description part",
    "role": "My role in that project",
    "url": EcoPizzaCaseStudy // <-- React component, not a path string
  },
  {
    "image": Squared,
    "name": "The UX portfolio item name",
    "description": "This is description part",
    "role": "My role in that project",
    "url": SquaredCaseStudy // <-- React component, not a path string
  }
];

The imported components should be rendered by a Route component and the link should specify a target path string.

You'll need to explicitly render a route for the work projects you want to link to.

Example:

Update the work data to include the element you want to render on a specific route, and then set the URL path you want it to render on.

import EcoPizza from "../assets/project-icons/ecoPizza.webp";
import Squared from "../assets/project-icons/Squared.webp";
import { EcoPizzaCaseStudy, SquaredCaseStudy } from "./case-studies";

const WorkData = [
  {
    image: EcoPizza,
    name: "The UX portfolio item name",
    description: "This is description part",
    role: "My role in that project",
    element: <EcoPizzaCaseStudy />, // <-- route element
    path: "eco-pizza", // <-- route path
  },
  {
    image: Squared,
    name: "The UX portfolio item name",
    description: "This is description part",
    role: "My role in that project",
    element: <SquaredCaseStudy />,
    path: "squared",
  }
];

export default WorkData;

The WorkCard component will use the path to navigate relative from the "/work" path, i.e. to "/work/eco-pizza".

const Work = () => {
  return (
    <div className="work">
      <section className="work-section">
        <div className="card">
          <h1 className="underline">My portfolio</h1>
          <p>Here are the case studies of my projects...</p>

          <div className="grid-layout grid-2">
            {
              WorkData.map((val) => {
                return (
                  <WorkCard
                    key={val.path}
                    path={val.path} // <-- path path through
                    image={val.image}
                    name={val.name}
                    description={val.description}
                    role={val.role}
                  />
                );
              })
            }
          </div>
        </div>
      </section>
    </div>
  );
}
const WorkCard = (props) => {
  return (
    <NavLink to={props.path} className="tile-card">
      <img src={props.image} alt={props.name} />
      <div className="details">
        <h2>{props.name}</h2>
        <p className="description" title={props.description}>
          {props.description}
        </p>
        <h4 className="role" title={props.role}>Role: {props.role}</h4>
      </div>
    </NavLink>
  );
}

Map the WorkData array to the project routes.

...
import WorkData from "./WorkData";
...

function App() {
  return (
    <div className="App">
      <Router>
        <Navigation />
        <main>
          <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/about" element={<About />} />
            <Route path="/work">
              <Route index element={<Work />} />
              {/* "/work/eco-pizza", "/work/squared", etc... */}
              {WorkData.map(({ path, element }) => (
                <Route key={path} {...{ path, element }} />
              ))}
            </Route>
            <Route path="/under-construction" element={<UnderConstruction />} />
            <Route path="/contact" element={<Contact />} />
            <Route path='*' element={<PageNotFound />}/>
          </Routes>
        </main>
        <Footer />
      </Router>
    </div>
  );
}
  • Related