사실 이건 포트폴리오에 추가시킬 예정은 아니었지만, nextjs13 + app router 환경에서 한번 해보는 것이 좋을 것 같아 추가해본다.
이전 프로젝트에서, 리액트 프로젝트에서 web worker로 시험 시간용 카운터를 만들었었는데 거기까지는 아니고 간단한 시계를 구현해보려고 한다.
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
간단하게 말해서 브라우저의 메인 쓰레드(프로젝트가 돌아가는)가 아닌 백그라운드 쓰레드에서 돌아가는 자바스크립트 코드이다. 서로 window,globalThis.postMessage와 onMessage event로 정보를 주고받으며 메인 쓰레드에서 자바스크립트 처리의 부하를 막기 위해 분산 처리(병렬 처리)를 해주는 기법이다.
거두절미하고 코드를 보자.
'use client';
import React, { useCallback, useEffect, useState } from 'react';
const Clock = () => {
const [isMounted, setIsMounted] = useState(false);
const [time, setTime] = useState(null);
const clockWorkerInit = useCallback(
() =>
new Worker(new URL('./clock.worker.ts', import.meta.url), {
type: 'module',
}), // 이 부분에서 워커 코드를 등록합니다.
[]
);
const handleMessage = useCallback(({ data }: { data: any }) => {
setTime(JSON.stringify(data));
}, []);
useEffect(() => {
setIsMounted(true);
}, []);
useEffect(() => {
if (isMounted && typeof window !== undefined) {
const worker = clockWorkerInit(); // 사용하는 기준은 컴포넌트가 마운트되고 윈도우 객체가 있다는 전제 하입니다. 브라우저의 윈도우 객체를 사용하므로 클라이언트 컴포넌트에서만 사용합니다.
worker.onmessage = handleMessage; // 워커에서 메시지를 보낸다면, 리액트단에서 onmessage로 받아서 사용할 수 있습니다.
return () => {
worker.terminate();
};
}
}, [clockWorkerInit, handleMessage, isMounted]);
return <div>{time}</div>;
};
export default Clock;
// components/clock/clock.worker.ts
globalThis.setInterval(() => {
globalThis.postMessage(new Date());
}, 1000);
// 이렇게 포스트메시지를 사용해서 데이터를 보낼 수 있습니다.
// self 객체도 가능합니다.
이런식으로 간단하게 1초에 한번 시간을 늘려주는 시계를 만들 수 있는데,
다음에는 조금더 여기에 살을 붙여보면 될 것 같다.
offscreenCanvas와 fetching을 통해 시간을 받아오는 정도를 진행할 것 같다.