From Flutter to React: How the AI Coding Renaissance Revived My Dev Journey

I’m a software developer turned business strategist. Back in 2014, I built my first website using jQuery and Bootstrap—scrappy, functional, and proudly self-taught. But over the years, family, business growth, and shifting priorities pulled me away from the dev scene. Web development became distant… until recently.

With the surge of AI tooling and the vibe coding renaissance, everything changed. Platforms like GitHub Copilot, Cursor, Claude Code, Windsurf, Bolt.new, and Replit reignited my curiosity. React and Next.js stood out as a gateway into modern frontend architecture.

While React was new to me, frontend logic wasn’t. I had previously built and published over 25 Android apps using Flutter. That knowledge was dusty—but tools like Replit and Copilot made getting back into the game feel smoother than ever. What followed was a journey through hooks, components, and an intriguing little thing called the Context API.

🌩️ The Initial Confusion: Theme Switching Gone Wrong

When I started learning React again, I marveled at how elegant yet confusing it could be. One particular feature gave me sleepless nights: the Context API, especially when using it to manage themes across a React app.

As a product builder or an AI developer, sharing state across your application without prop-drilling is essential. And understanding useContext() is non-negotiable.

Here’s my journey from confusion to clarity, and the practical solution that finally made things click.

Problem Statement: Prop Drilling Gets Ugly

Like many returning developers, I started by building a simple React app—an about-me page, a couple of headings, and a few paragraphs styled based on the user’s preferred theme. The logic was easy to grasp: I defined a theme state at the top level (light or dark) and tried to pass it down through components using props.

It worked… for a while. But then I added a header. And a page section. And a nested text component. Suddenly, every component was asking for theme, even ones that didn’t directly care about it.

Here’s what that looked like:


<Page theme={theme} />
<Header theme={theme} />

Then inside Page, and then inside Title:


<Title theme={theme} />
<Paragraph theme={theme} />

const Title = ({ theme, children }) => {
  return (
    <h1 style={{ color: theme === "dark" ? "white" : "black" }}>
      {children}
    </h1>
  );
};

Prop drilling felt like plumbing a leaky house. One upstream change required downstream rewiring.

That’s when I turned to React’s Context API—a way to share global state across components without prop chaos.

While React felt like new territory, I wasn’t a stranger to frontend frameworks. I’d spent years working with Flutter, and had shipped over 25 Android apps. That skill had started gathering dust… until I discovered a new wave of game-changing tools like Replit, Windsurf, Cursor, Claude Code, GitHub Copilot, Bolt.new, and so many others that reignited my love for building. Suddenly, coding wasn’t just efficient—it was exhilarating.

🧱 Building the Theme Context (Step-by-Step)

If you’re new to React Context, think of it as a broadcast system. You define a “channel” (ThemeContext), provide it with values (like theme), and let any component “subscribe” to it without manual prop passing.

1️⃣ Create the Context


import { createContext } from "react";
export const ThemeContext = createContext();

This sets up the channel. No data yet—just the frequency.

2️⃣ Set Up the ThemeProvider


import React, { useState } from "react";
import { ThemeContext } from "./ThemeContext";

export const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState("light");

  const toggleTheme = () => {
    setTheme(prev => (prev === "dark" ? "light" : "dark"));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

React requires hooks to be inside components—don’t define useState globally.

3️⃣ Create a Custom Hook for Easy Consumption


import { useContext } from "react";
import { ThemeContext } from "./ThemeContext";

export const useTheme = () => useContext(ThemeContext);

Then in any component:


const { theme, toggleTheme } = useTheme();

This keeps your UI logic clean and centralized.

🧵 Why My Theme Toggle Was Buggy (Closure & Batching in Action)

One of my early bugs looked like this:


function toggleTheme() {
  setTheme(theme === "dark" ? "light" : "dark");
}

Seems logical, right?

React disagreed. I’d see inconsistent toggles. Sometimes the theme would double-flip or not switch at all.

🔍 The Problem: Closure Scope + Batching

In JavaScript, closures “remember” variables from when they were created—even if they’ve changed since. My function was working with an outdated copy of theme, especially when React batched multiple state updates into one render cycle.

The fix?


setTheme(prev => (prev === "dark" ? "light" : "dark"));

This guarantees the latest value—making toggling bulletproof.

🧪 Classic Batched State Bug Example

Here’s a bug I’d seen in counters too:


setCount(count + 1);
setCount(count + 1);

You expect the count to be 2, but it stays 1. Why? Both lines use stale count.

✅ The fix:


setCount(c => c + 1);
setCount(c => c + 1);

Each updater receives the freshest value—even when batched.

🎨 Building a Themed Component

Once my context was solid, building reactive UI was seamless.

Example: A title that adjusts color based on the theme:


const Title = ({ children }) => {
  const { theme } = useTheme();
  return (
    <h1 style={{ color: theme === "light" ? "black" : "white" }}>
      {children}
    </h1>
  );
};

And a layout wrapper:


const PageWrapper = ({ children }) => {
  const { theme } = useTheme();
  return (
    <div style={{ backgroundColor: theme === "light" ? "#fff" : "#111" }}>
      {children}
    </div>
  );
};

No props. No confusion. Just clean, context-driven styling.

❌ Mistakes I Made (and You Can Dodge)

Here’s a quick table of the roadblocks I hit and how I fixed them:

MistakeWhy It FailsFix It With
Defining useState() outside a componentReact throws errors because hooks need a valid scopeMove hooks into your ThemeProvider component
Passing props unnecessarilyLeads to bloated hierarchies and duplicationUse context + custom hook
Using stale theme in toggleClosures capture outdated state during batchingUse setTheme(prev => ...)
Overstyling components manuallyHard to maintain across layoutsUse conditional styles from context
Writing useContext("dark")Context expects an object, not a static stringAlways use your ThemeContext reference

💼 Real-World Use Cases

Use CaseWhere It FitsWhy It Works
SaaS DashboardsDark mode switcher for admin panelsConsistent theming without manual config
AI Dev ToolsOverlay, system, or performance viewsGlobal mode switching for UX
Startup SitesPersonalization settingsImproves branding and accessibility
Reader-Focused BlogsNight mode for reduced eye strainUser-centric design choices

✅ Quick Reference Cheatsheet

Do ThisDon’t Do This
useContext(ThemeContext)useContext("dark")
setTheme(prev => ...)setTheme(theme === "dark")
Wrap app in ThemeProviderUse context without a wrapper
Use useTheme() hookDrill props across components

🔚 Final Thoughts: From Friction to Flow

This theme toggle journey reminded me of what I love about dev work: solving meaningful problems with thoughtful architecture. React’s Context API unlocked a new layer of clarity in my app logic. Hooks became less mysterious, closures more predictable, and the UI… beautifully reactive.

Whether you’re crafting SaaS dashboards, AI-powered visualizers, or blog UIs, mastering context will save you hours and scale your app gracefully. I fumbled through it—so you don’t have to.

Want a starter repo, demo link, or companion Notion template to build your own theme toggler? I’ve got plenty more ideas where this came from ⚛️🛠️

Leave a Reply

Your email address will not be published. Required fields are marked *