DEV Community

Cover image for Building Pomodoro Flow: How I Made a YouTube-Integrated Pomodoro Timer with React, Zustand, and TypeScript
keni
keni

Posted on

Building Pomodoro Flow: How I Made a YouTube-Integrated Pomodoro Timer with React, Zustand, and TypeScript

Introduction

Hi everyone, I’m Keni (@keni_solopreneur).

This is my first post on DEV, and I’d like to share the journey of creating my side project: Pomodoro Flow 🍅 — a minimalist Pomodoro timer that integrates YouTube directly.

I’m not a professional software engineer by trade. I actually started this project simply because I wanted a focus timer that could play my favorite YouTube music without having to constantly switch tabs. What started as a small frustration turned into a real project where I learned React, TypeScript, Zustand, and a lot about building in public.

In this post, I’ll go through:

  • Why I decided to build this tool in the first place
  • The stack I chose (React, Vite, TypeScript, Zustand) and why
  • How I integrated YouTube with react-youtube and the IFrame API
  • How Zustand made state management so much simpler
  • The challenges I faced and lessons I learned along the way
  • What I’m planning next for this project

The Problem: Timer + YouTube = Too Many Tabs

I’ve always liked the Pomodoro Technique: 25 minutes of focused work, followed by a short break. It helps me stay on track, especially when working on personal projects after my day job.

But there was always a catch. Most Pomodoro apps provide built-in music or ambient sounds. And while that works for some people, it never worked for me. Some days I need lo-fi hip hop, other days it’s rain sounds, and sometimes it’s even game commentary running in the background. The music of the day matters a lot for my focus.

At first, my workflow looked like this:

  • One tab open for the timer
  • Another tab open for YouTube
  • Constant switching back and forth

It was distracting and killed my flow.

So I thought: what if I just build the tool I need myself?


Learning React in 3 Weeks (as a Non-Engineer)

Here’s the honest part: I had zero web development experience before this.

I’m a full-time automation engineer, but my work is more about Python and PLCs than frontend. So, starting with React and TypeScript felt intimidating.

To get started, I did a few things:

  • Watched YouTube tutorials on React basics
  • Took a Udemy course to understand component-based development
  • Used ChatGPT and Cline (AI coding assistant) to accelerate learning
  • Built small test components before putting them into my app

Three weeks later, I had my MVP: a Pomodoro timer with a working YouTube embed.

After another three weeks of refining the UI, fixing bugs, and polishing the UX, I had something that I felt confident enough to share: Pomodoro Flow.


Tech Stack

  • React (with Vite) → Fast, modern, and great DX
  • TypeScript → Type safety made me more confident, especially as a beginner
  • Zustand → Lightweight and intuitive state management
  • react-youtube → A simple wrapper around the YouTube IFrame Player API

I chose these tools because I wanted something minimal but reliable. Redux felt like overkill for this project, and Context API alone wasn’t enough for the level of state management I needed.


Key Feature: Syncing Timer and YouTube Playback

The core of Pomodoro Flow is simple:

  • When the timer starts → play the YouTube video
  • When the timer pauses → pause the video

Here’s the simplified implementation:

import YouTube from 'react-youtube';
import { useTimerStore } from './stores/timerStore';
import { useYouTubeStore } from './stores/youtubeStore';
import { useEffect } from 'react';

const YouTubePlayer = () => {
  const { isRunning } = useTimerStore();
  const { player, setPlayer } = useYouTubeStore();

  useEffect(() => {
    if (!player) return;
    isRunning ? player.playVideo() : player.pauseVideo();
  }, [isRunning, player]);

  const onReady = (event: any) => {
    setPlayer(event.target);
  };

  return <YouTube videoId="YOUR_VIDEO_ID" onReady={onReady} />;
};
Enter fullscreen mode Exit fullscreen mode

Why Zustand?

I briefly considered Redux, Context API, and even Recoil. In the end, Zustand won because:

  • It’s lightweight (no boilerplate, just functions and hooks)
  • State slices make it easy to subscribe only to what you need
  • It plays nicely with TypeScript

Here’s a simple example of the timer store:

// src/stores/timerStore.ts
import { create } from 'zustand';

type TimerState = {
  isRunning: boolean;
  start: () => void;
  stop: () => void;
};

export const useTimerStore = create<TimerState>((set) => ({
  isRunning: false,
  start: () => set({ isRunning: true }),
  stop: () => set({ isRunning: false }),
}));
Enter fullscreen mode Exit fullscreen mode

Challenges and Solutions

YouTube Player Load Timing

One issue I faced was that sometimes the YouTube player wasn’t fully ready when the timer state changed.

Solution: Only control playback once onReady sets the player instance in Zustand.

Avoiding Unnecessary Re-renders

Another problem was re-rendering too many components when state changed.

Solution: With Zustand, I could subscribe only to the specific state slice (isRunning) that I needed, preventing unrelated UI updates.

TypeScript with Third-Party Libraries

The react-youtube package didn’t provide perfect type support.

Solution: I wrote wrapper types and interfaces to ensure type safety across my codebase.


The Result: Pomodoro Flow

After about 6 weeks of learning and building, the result is Pomodoro Flow — a minimal Pomodoro timer that integrates directly with YouTube.

👉 Try it here: pomodoro-flow.com

Key features include:

  • Paste any YouTube link you want
  • Play your favorite music, ASMR, or ambient sounds while working
  • No more switching tabs — just one clean space to focus

What’s Next?

This is still just an MVP, but I already have a roadmap in mind:

  • Spotify and other music service integrations
  • Simple task management features
  • Analytics to visualize productivity sessions

I’ll continue building in public and sharing progress here on Dev.to. 🚀


Final Thoughts

This project started from a small personal frustration, but it became a great learning journey with React, TypeScript, Zustand, and the YouTube API.

If you’re considering starting your own side project, my advice is simple: just start.

You’ll learn far more than you expect.

👉 Try Pomodoro Flow: https://pomodoro-flow.com

👉 Follow me here on Dev.to — I’ll be sharing more updates and lessons learned.

Thanks for reading, and happy focusing! 🍅

Top comments (0)