튜토리얼 — 디지털 시계 만들기

카운트는 버튼을 눌러야 바뀌었죠. 이번엔 버튼 없이 저절로 바뀌는 걸 만들어 봅니다. 1초마다 똑딱이는 시계입니다. useState로 시각을 담고, useEffect로 타이머를 켜고, 앞 절에서 배운 정리 함수로 타이머를 끕니다.
개념
시계가 움직이려면 두 가지가 필요합니다.
- 지금 몇 시인지 기억할 곳 →
useState - 1초마다 시각을 새로 고치는 장치 →
useEffect안의setInterval
setInterval은 딱 "켜면 끄기"가 짝인 효과입니다. 켜 두기만 하고 끄지 않으면, 시계 컴포넌트가 사라진 뒤에도 타이머가 계속 돌면서 사라진 컴포넌트의 상태를 바꾸려 합니다. 그래서 정리 함수에서 clearInterval로 꼭 꺼 줍니다.
함께 해보기
1단계 — 시계 컴포넌트 만들기
components/Clock.tsx 파일을 만듭니다.
"use client"; import { useState, useEffect } from "react"; export default function Clock() { // 1. 지금 시각을 상태로 — 처음 값은 "만들어진 순간" const [now, setNow] = useState(new Date()); // 2. 타이머 켜기 (마운트 때 한 번) useEffect(() => { const timerId = setInterval(() => { setNow(new Date()); // 1초마다 새 시각으로 교체 → 다시 그려짐 }, 1000); // 3. 타이머 끄기 (정리 함수) return () => { clearInterval(timerId); console.log("정리 실행: 타이머를 껐습니다"); }; }, []); // 의존성 빈 배열 → 켜기 한 번, 끄기 한 번 return <h1>{now.toLocaleTimeString("ko-KR")}</h1>; }
여기서 의존성 배열이 빈 배열 [] 인 게 핵심입니다. 카운트 예제에서는 [count]라 count가 바뀔 때마다 효과가 다시 돌았죠. 빈 배열은 "바뀔 의존성이 없다"는 뜻 — 효과는 마운트 때 딱 한 번 켜지고, 정리는 언마운트 때 딱 한 번 실행됩니다.
setNow로 상태를 바꾸면 컴포넌트가 다시 그려집니다. 그래서 1초마다 화면의 시각이 갱신돼요. 타이머가 컴포넌트를 다시 실행시키는 게 아니라, 상태 변경이 다시 그리는 겁니다.
2단계 — 페이지에 올리기
app/clock/page.tsx를 만듭니다.
"use client"; import { useState } from "react"; import Clock from "@/components/Clock"; export default function ClockPage() { const [showClock, setShowClock] = useState(true); return ( <main style={{ padding: 24 }}> <h2>디지털 시계</h2> {/* showClock이 true일 때만 시계를 그림 */} {showClock && <Clock />} <button onClick={() => setShowClock(!showClock)}> {showClock ? "시계 숨기기" : "시계 보이기"} </button> </main> ); }
시계를 숨겼다 보였다 하는 버튼을 일부러 넣었습니다. 정리 함수가 실행되는 순간을 눈으로 보려고요.
3단계 — 확인
/clock을 열고 콘솔을 봅니다.
- 시각이 1초마다 바뀝니다 ✅
- "시계 숨기기" 를 누르면 →
Clock이 화면에서 사라지고(언마운트), 콘솔에정리 실행: 타이머를 껐습니다가 찍힙니다. - "시계 보이기" 를 다시 누르면 →
Clock이 새로 마운트되고 타이머가 다시 켜집니다.
(시계 보임 — 타이머 켜짐, 똑딱똑딱) 정리 실행: 타이머를 껐습니다 ← "숨기기" 누름 (언마운트) (시계 사라짐 — 타이머 꺼짐, 조용함) 정리 실행: 타이머를 껐습니다 ← "보이기" 후 다시 "숨기기"
확인 ✅ — 정리 함수가 언마운트 때 실행되는 걸 직접 봤습니다. 만약 clearInterval을 빼먹었다면, 숨긴 뒤에도 타이머가 계속 돌면서 콘솔에 경고가 떴을 겁니다 ("사라진 컴포넌트의 상태를 바꾸려 한다").
개발 모드에서는 마운트 직후
정리 실행이 한 번 더 보일 수 있습니다. 앞 절에서 본 그 검사예요 — 정리 함수를 제대로 짰는지 React가 확인해 주는 겁니다. 놀라지 마세요.
정리
useState는 무엇을 기억할지(현재 시각),useEffect는 언제 무엇을 할지(1초마다 갱신)를 맡습니다.setInterval로 켠 타이머는 정리 함수의clearInterval로 반드시 꺼 줍니다.- 의존성 배열이
[]면 → 효과는 마운트 때 한 번, 정리는 언마운트 때 한 번. - 화면이 갱신되는 진짜 이유는 타이머가 아니라
setNow(상태 변경) 입니다.
연습 거리
시계를 다 만들었다면 이어서 해 보세요.
now.toLocaleDateString("ko-KR")로 날짜도 같이 표시하기- 1000ms를 100ms로 바꿔 보고, 밀리초까지 보이게 하기
console.log로 "효과 실행"도 찍어, 켜기/끄기 짝이 맞는지 카운트 예제처럼 확인하기

댓글
댓글을 작성하려면 이 필요합니다.