Objective - Load same page layout from context provider with different data for each project.
I'm currently working on a Portfolio Website using React, React-Router, and React-Context. I need to be able to reuse the singleProject page layout but load different data depending on which card was selected.
Here's how the routing is currently handled. Each project card has it's own dynamic link based off it's title.
Single Project Card:
//ProjectSingle.js (Card)
import { motion } from 'framer-motion';
import { Link } from 'react-router-dom';
const ProjectSingle = ({ title, category, image }) => {
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1, delay: 1 }}
transition={{
ease: 'easeInOut',
duration: 0.7,
delay: 0.15,
}}
>
<Link to={`/projects/${title}`} aria-label="Single Project">
<div className="rounded-xl shadow-lg hover:shadow-xl cursor-pointer mb-10 sm:mb-0 bg-secondary-light dark:bg-ternary-dark">
<div>
<img
src={image}
className="rounded-t-xl border-none"
alt="Single Project"
/>
</div>
<div className="text-center px-4 py-6">
<p className="font-general-medium text-lg md:text-xl text-ternary-dark dark:text-ternary-light mb-2">
{title}
</p>
<span className="text-lg text-ternary-dark dark:text-ternary-light">
{category}
</span>
</div>
</div>
</Link>
</motion.div>
);
};
export default ProjectSingle;
The router handles this and renders a singleProject (Page) component which then calls the singleProject (Page) context provider.
Routes:
function App() {
return (
<AnimatePresence>
<div className=" bg-secondary-light dark:bg-primary-dark transition duration-300">
<Router>
<ScrollToTop />
<AppHeader />
<Routes>
<Route path="/" element={<Home />} />
<Route path="projects" element={<Projects />} />
<Route
path='projects/:title'
element={<ProjectSingle />}
/>
<Route path="about" element={<About />} />
<Route path="contact" element={<Contact />} />
</Routes>
<AppFooter />
</Router>
<UseScrollToTop />
</div>
</AnimatePresence>
);
}
export default App;
Single Project Page:
const ProjectSingle = () => {
const projTitle = useParams();
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1, delay: 1 }}
transition={{
ease: 'easeInOut',
duration: 0.6,
delay: 0.15,
}}
className="container mx-auto mt-5 sm:mt-10"
>
<SingleProjectProvider data={projTitle} >
<ProjectHeader />
<ProjectGallery />
<ProjectInfo />
{/* <ProjectRelatedProjects /> */}
</SingleProjectProvider>
</motion.div>
);
};
export default ProjectSingle;
Finally, the singleProjectProvider takes in the title which I'd planned to use to search for the specific singleProject data. Here's my current
Context provider for the singleProject (Page):
import { useState, createContext } from 'react';
import { singleProjectData as singleProjectDataJson } from '../data/singleProjectData';
const SingleProjectContext = createContext();
export const SingleProjectProvider = ({ children }, props) => {
const title = props.data;
const [singleProjectData, setSingleProjectData] = useState(
singleProjectDataJson
);
return (
<SingleProjectContext.Provider
value={{ singleProjectData, setSingleProjectData }}
>
{children}
</SingleProjectContext.Provider>
);
};
export default SingleProjectContext;
Finally, this is the SingleProjectData.js where I need to select the correct data to use for the context provider provided a title. I've shortened it a lot for readers sake.
singleProjectData.js
export const singleProjectData = [
{
ProjectHeader: {
title: 'React & Tailwindcss Portfolio',
publishDate: 'Jul 26, 2021',
tags: 'UI / Frontend',
},
},
{
ProjectHeader: {
title: 'MechanALink',
publishDate: 'Jul 26, 2021',
tags: 'UI / Frontend',
},
},
];
Summary: After the title is passed into the context provider, I wish to then filter and select only the data that corresponds to the correct title. Then use this data to fill out the Context Provider's children.
Apologies for the lengthy question, there's a lot of routing and redirecting going on here.
Well:
projTitle
is an object{ title }
):({ children }, props)
should be corrected to({ title, children })
.I would use an id in place of a title with spaces and special characters (more resilient to URLs escaping).
In most cases: context should be avoided unless really necessary: it does seem to be a good use case, and bring more complexity that necessary ;