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.
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:
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>
);
}