I am fairly new to Next.js, React hooks and everything. I am wondering if I am doing this right, I am making a customizable portfolio site using Next.js, Flowbite-react, and TailwindCSS on the front end and Django on the back end.
For testing, I have set up a Navbar, that opens up modals and gets the user's input.
When I click on the Modal, it gets rid of my ability to scroll down the page.
My components > Navbar.js looks like this, the {modalContent being passed in is basically separate forms in components}
import {Avatar, Dropdown, Modal, Navbar} from "flowbite-react";
import { useState } from 'react';
import EditEducation from "@/components/EditEducation";
import EditExperience from "@/components/EditExperience";
import EditSkills from "@/components/EditSkills";
export default function Nav({ setEducation, setExperience, setSkills }) {
const [modalVisible, setModalVisible] = useState(false);
const [modalContent, setModalContent] = useState(null);
const openModal = (content) => {
setModalContent(content);
setModalVisible(true);
};
const closeModal = () => {
setModalVisible(false);
setModalContent(null);
}
const onEducationChange = (education) => {
setEducation(education);
}
const onExperienceChange = (experience) => {
setExperience(experience);
}
const onSkillsChange = (skills) => {
setSkills(skills)
}
return (
<>
<Navbar
fluid={true}
>
<div className='flex md:order-2'>
<Dropdown
arrowIcon={false}
inline={true}
label={<Avatar alt='User settings' img={null} rounded={true}/>} >
<Dropdown.Header>
<span className='block text-sm'>
tester
</span>
<span className='block truncate text-sm font-medium'>
test@test.com
</span>
</Dropdown.Header>
<Dropdown.Item>
Dashboard
</Dropdown.Item>
<Dropdown.Item>
Settings
</Dropdown.Item>
<Dropdown.Item>
Sign Out
</Dropdown.Item>
</Dropdown>
<Navbar.Toggle/>
</div>
<Navbar.Collapse>
<Navbar.Link href='/' active={true}>
Home
</Navbar.Link>
<Navbar.Link href='#' onClick={() => openModal(<EditEducation
onEducationChange={onEducationChange}
onClose={closeModal}/>)}>
Education
</Navbar.Link>
<Navbar.Link href='#' onClick={() => openModal(<EditExperience
onExperienceChange={onExperienceChange}
onClose={closeModal}/>)}>
Experience
</Navbar.Link>
<Navbar.Link href='#' onClick={() => {
openModal(
<EditSkills
onSkillsChange={onSkillsChange}
onClose={closeModal}
/>)}}>
Skills
</Navbar.Link>
</Navbar.Collapse>
</Navbar>
{modalVisible && (
<Modal
id='edit_modal'
show={modalVisible}
size='md'
popup={true}
onClose={closeModal}>
<Modal.Header/>
<Modal.Body>{modalContent}</Modal.Body>
</Modal>
)}
</>
)
}
And this data is going up into my pages > index.js, then back down into the components > Portfolio.js
import React, { useState } from 'react'
import Hero from "@/components/Hero";
import Footer from "@/components/Footer";
import Portfolio from "@/components/Portfolio";
import Nav from "@/components/Nav";
function Home() {
const [education, setEducation] = useState([]);
const [experience, setExperience] = useState([]);
const [skills, setSkills] = useState([]);
return (
<>
<Nav
setEducation={setEducation}
setExperience={setExperience}
setSkills={setSkills}
/>
<Hero/>
<Portfolio
education={education}
experience={experience}
skills={skills}
/>
<Footer/>
</>
)
}
export default Home
This is what my components > Portfolio.js looks like (Where the GSAP and parallax scrolling live)
import React, {useEffect, useRef} from 'react';
import { ParallaxProvider, Parallax } from 'react-scroll-parallax';
import { gsap } from 'gsap';
import ScrollTrigger from 'gsap/dist/ScrollTrigger';
const PortfolioSection = ({backgroundRef,
sectionRef,
triggerRef,
education,
experience,
skills}) => {
const renderEducationContent = () => {
return education.map((edu, index) => (
<div key={index}>
<h4>Degree: {edu.degree}</h4>
<p>University: {edu.university}</p>
<p>Year: {edu.year}</p>
</div>
));
};
const renderExperienceContent = () => {
return experience.map((exp, index) => (
<div key={index}>
<h4>Company: {exp.company}</h4>
<p>Position: {exp.position}</p>
<p>Duration: {exp.duration}</p>
</div>
));
};
const renderSkillsContent = () => {
return skills.map((skill, index) => (
<div key={index}>
<h4>Skill: {skill}</h4>
</div>
));
};
const sections = [
{title: 'Education', content: renderEducationContent()},
{title: 'Experience', content: renderExperienceContent()},
{title: 'Skills', content: renderSkillsContent()},
];
return (
<>
<div className="scroll-section-outer">
<ParallaxProvider scrollAxis="horizontal">
<div ref={triggerRef}>
<div ref={sectionRef} className="scroll-section-inner">
{sections.map((section, index) => (
<Parallax y={[-30, 30]} key={index}>
<div
ref={backgroundRef}
style={{
backgroundImage: "url('/Forest.png')",
backgroundSize: "cover",
backgroundPosition: "center",
width: "2000px",
}}
className="h-screen"
>
<section className="scroll-section">
<h3>{section.title}</h3>
<div>{section.content}</div>
</section>
</div>
</Parallax>
))}
</div>
</div>
</ParallaxProvider>
</div>
</>
);
}
const Portfolio = ({ education, experience, skills }) => {
const backgroundRef = useRef(null)
const sectionRef = useRef(null)
const triggerRef = useRef(null)
gsap.registerPlugin(ScrollTrigger);
useEffect(() => {
const pin = gsap.fromTo(sectionRef.current, {
translateX: 0
}, {
// increase and decrease based on section
translateX: "-300vw",
ease: "none",
direction: 1,
scrollTrigger: {
trigger: triggerRef.current,
start: "top top",
// 2000 px at the top of the next section
end: "2000 top",
scrub: 0.6,
pin: true
}
})
// kills animation when the component gets unordered
return () => {
pin.kill()
}
}, {})
return (
<PortfolioSection
backgroundRef={backgroundRef}
sectionRef={sectionRef}
triggerRef={triggerRef}
education={education}
experience={experience}
skills={skills}
/>
);
};
export default Portfolio;
Am I doing this right? Everything seems to work, except for the Modal somehow breaking my ability to scroll for some reason.
I have tried to add prevent defaults to the openmodal function, I have tried to put the form right on the main page, and that doesn't break it. For some reason, the only thing that breaks my scrolling is clicking on the Nav.Link, and opening the modal.