Issue
I'm learning React framework and I'm stuck on a question. I have this array which contains pieces of information about some templates I built.
const template = \[
{
title: 'firstPortfolio',
url: 'first_portfolio',
id: 1,
img: require('../templates-images/firstPortfolio.png')
},
{
title: 'leadershipEvent',
url: 'leadership_event',
id: 2,
img: require('../templates-images/leadership-event.png')
},
{
title: 'digimedia',
url: 'digimedia',
id: 3,
img: require('../templates-images/digimedia.png')
},
{
title: 'arsha',
url: 'arsha',
id: 4,
img: require('../templates-images/arsha.png')
}
\];
export default template;
I've imported it in App.js (I know that the code makes a little pity and does not reflect the logic on which React is based, I'm new):
import './App.css';
import { useEffect, useState } from 'react';
import { Nav } from 'react-bootstrap';
import Container from 'react-bootstrap/Container';
import Navbar from 'react-bootstrap/Navbar';
import HomePage from './pages/Homepage';
import Portfolio from './pages/Portfolio';
import Template from './pages/Template';
import template from './assets/js/templates';
import { Routes, Route, Link } from 'react-router-dom';
function App() {
const [menuBtn, setMenuBtn] = useState(true);
useEffect(() => {
const menuBtn = document.getElementById('menuBtn');
const lineOne = document.getElementById('lineOne');
const lineTwo = document.getElementById('lineTwo');
const lineThree = document.getElementById('lineThree');
const lineOneAnimation = [
{ width: '30px', top: '18px', transform: 'rotate(0deg)' },
{ width: '30px', top: '26px', transform: 'rotate(45deg)' }
];
const lineTwoAnimation = [
{ width: '20px', top: '26px' },
{ width: '0' }
];
const lineThreeAnimation = [
{ width: '10px', top: '34px', transform: 'rotate(0deg)' },
{ width: '30px', top: '26px', transform: 'rotate(-45deg)' }
];
const menuAnimationTiming = {
duration: 200,
iterations: 1,
fill: 'both'
};
menuBtn.addEventListener('click', () => {
if (menuBtn.classList.contains('collapsed')) {
setTimeout(function () {
lineOne.animate(lineOneAnimation, menuAnimationTiming);
}, 200);
lineTwo.animate(lineTwoAnimation, menuAnimationTiming);
setTimeout(function () {
lineThree.animate(lineThreeAnimation, menuAnimationTiming);
}, 200);
} else {
lineOne.animate(lineOneAnimation, menuAnimationTiming).reverse();
lineTwo.animate(lineTwoAnimation, menuAnimationTiming).reverse();
lineThree.animate(lineThreeAnimation, menuAnimationTiming).reverse();
}
});
})
const templateRoutePath = function () {
for (let i = 0; i < template.length; i++) {
return `/portfolio/${template[i].title}`;
}
}
const pathGit = function () {
for (let i = 0; i < template.length; i++) {
return `https://andrea-mazza.github.io/template/${template[i].url}/`;
}
}
// const templateKey = function () {
// for (let i = 0; i < template.length; i++) {
// return `${template[i].id}`;
// }
// }
return (
<div className="App">
<header className='container-fluid'>
<Navbar expand="lg">
<Container fluid>
<Navbar.Brand href="/">FreeAttitude</Navbar.Brand>
<Navbar.Toggle onClick={setMenuBtn} aria-controls="basic-navbar-nav" id="menuBtn">
<span id="lineOne" className="line"></span>
<span id="lineTwo" className="line"></span>
<span id="lineThree" className="line"></span>
</Navbar.Toggle>
<Navbar.Collapse id="basic-navbbar-nav">
<Nav className="menu-items">
<Link to="/" className="nav-item">Home</Link>
<Link to="/portfolio" className="nav-item">Portfolio</Link>
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
</header>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/portfolio" element={<Portfolio />} />
<Route path={`/portfolio/:templateTitle`} element={<Template gitPath={pathGit.apply()} />} />
</Routes>
</div>
);
}
export default App;
The Route Component in question is the last one, which render the Template component. The Template Component's code is this:
import template from "../assets/js/templates";
function Template(props) {
const title = function () {
for (let i = 0; i < template.length; i++) {
return `${template[i].title}`
}
}
return (
<iframe src={props.gitPath} title={title.apply()} />
);
}
export default Template;
What am I trying to do? I'd like to show the Template Component whit the right gitPath props, according to the path of the Route Component.
What is the problem? This work but only the first <iframe> is shown, for all the Route that starts with '/portfolio/'. For example: If I type: '/portfolio/firstPortfolio' I can see an iframe element that shows the template I previously built and which is stored on GitHub. However, if I type: '/portfolio/leadershipEvent/' I see again an iframe that shows firstPortfolio project instead of an iframe for the leadershipEvent project.
I have attached some pictures for clarity:
I actually see the project with the correct URL:
URL is correct but the src iframe's attribute points again to the firstPortfolio github's url
Solution
I solved the question. To dynamically create a Route Component and display the right project based on the URL I wrote this code in the 'App.js' file:
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/portfolio" element={<Portfolio />} />
{/* The JSX belove is used to dynamycally create Route Component for each template */}
{
template.map(element => {
return (
<Route path={`/portfolio/${element.title}`} key={element.id} element={<Template gitPath={`https://andrea-mazza.github.io/template/${element.url}/`} />} />
);
})
}
</Routes>
Answered By - Andrea
Answer Checked By - - Clifford M. (ReactFix Volunteer)