My First React Project (Part 3): Reusable Components, Framer Motion Animation, and Key Lessons Learned
Then I reused it inside my LandingPage component:
function LandingPage() { return( <> {/* other LandingPage JSX */} <section id="features"> <Section backgroundColor="section--gray-100" title="Why choose Digitalbank?" description="We leverage Open Banking to turn your bank account into your financial hub. Control your finances like never before." > <Features /> </Section> </section> <section id="articles"> <Section backgroundColor="section--gray-50" title="Latest Articles" > <Articles /> </Section> </section> {/* other LandingPage JSX */} </> ); }
This made the code feel much cleaner and more scalable. If I ever add another section with the same structure, I can simply reuse the component instead of rewriting markup from scratch.
That was one of the biggest “React mindset” moments during the project.
Adding Animations with CSS + React Hooks
For the Hero Section, I wanted a fade-in + slide-up animation when the mockup image loads.
In plain HTML/CSS, I’d rely on CSS animations triggered by page load. But in React, I used the useState hook with the onLoad event:
function HeroSection() { const [imageLoaded, setImageLoaded] = useState(false); return( <section className={`hero ${imageLoaded ? "loaded" : ""}`} aria-labelledby="hero-title" > {/* other hero JSX */} <img src={mockup} alt="Mockup of a banking app on mobile phones" className="hero__mockup" onLoad={() => setImageLoaded(true)} /> {/* other hero JSX */} </section> ); }
Here’s how it works:
- imageLoaded starts as false
- Once the image finishes loading, setImageLoaded(true) runs
- React adds the loaded class
- The CSS animation then triggers
This ensures the animation plays only after the image is fully ready, creating a smoother experience.
Staggered Animations with Framer Motion
The last animation I added was a staggered reveal for the article cards.
Instead of writing complex JavaScript with the Intersection Observer API, I used Framer Motion, which is declarative and integrates beautifully with React.
I defined variants for the parent container and child cards:
// Section component const containerVariants = { hidden: {}, visible: { transition: shouldReduceMotion ? {} : { staggerChildren: 0.12 } } }; // Articles component const cardVariants = { hidden: { opacity: shouldReduceMotion ? 1 : 0, y: shouldReduceMotion ? 0: 30 }, visible: { opacity: 1, y: 0, transition: shouldReduceMotion ? { duration: 0 } : { duration: 0.5, ease: "easeOut" } } };
Then applied them:
// Section component <motion.div variants={containerVariants} initial={shouldReduceMotion ? false : "hidden"} whileInView={shouldReduceMotion ? undefined : "visible"} viewport={{ once: true, amount: 0.2 }} className="section__grid" > {children} </motion.div> // Articles component <motion.article variants={cardVariants} className="article__card" key={article.id} > {/* article content */} </motion.article>
The result is a smooth, staggered animation in which each card slides upward one after another.
What I liked most was how simple Framer Motion made everything. The whileInView prop automatically handles scroll-triggered animations without needing to manually wire up observers.
Key Lessons Learned
1. Component Architecture
Breaking the UI into reusable pieces made the project much easier to manage.
Each component owns its own markup and logic, while the LandingPage component simply arranges sections together.
That separation made the codebase feel more organized and scalable.
2. React Hooks
Hooks became essential throughout this project.
I used:
- useState for menu toggles and image load tracking
- useEffect for disabling page scroll when the mobile menu is open
Before this project, hooks felt abstract while reading documentation. Building something real made them finally “click” for me.
3. Props and State Management
Passing props down and lifting state up are core React patterns that I practiced repeatedly here.
The more I used them, the more I understood how React components communicate and stay flexible.
4. CSS Was Harder Than React
Ironically, CSS ended up being the hardest part of the project.
I spent far more time dealing with:
- layouts
- spacing
- positioning
- responsiveness
- overflow issues
than writing actual React logic.
Using functions like clamp() across breakpoints helped improve my responsive design skills a lot.
5. Accessibility Matters
I also tried to make the project more accessible by:
- adding aria-labelledby
- respecting prefers-reduced-motion
- using Framer Motion’s useReducedMotion hook
This reminded me that accessibility shouldn’t be treated as an afterthought.
Final Thoughts
This project tested both my CSS fundamentals and React basics.
Even though it wasn’t the most React-heavy application, it gave me hands-on experience with:
- component architecture
- hooks
- reusable layouts
- Framer Motion
- accessibility considerations
More importantly, it taught me persistence.
I got stuck multiple times. I rewrote code, researched solutions, broke layouts, and made mistakes, but I kept going until everything finally came together.
And honestly, that might be the biggest lesson from this entire project.
I now feel much more confident building future React applications, and I can already see how much more structured my approach has become compared to when I started.
On to the next project!
Fuente: Artículo original