[Next.js] 나만의 학습 블로그 만들기 #2 - 방문자 수 측정하기(feat. Firebase)
![[Next.js] 나만의 학습 블로그 만들기 #2 - 방문자 수 측정하기(feat. Firebase)](https://cdn.hashnode.com/res/hashnode/image/upload/v1752471304613/f2b6d5fe-196f-4b21-b37d-505cc8ae02eb.png)
내용 기록 외에도 방문자 수랑 댓글 기능도 넣으려고 한다.!
이번 글에서는 방문자 수 측정 기능 구현을 적어보겠다🤭
나는 서버가 없으니 파이어베이스를 선택해줬다…!
- 파이어베이스 사이트에 들어가서 프로젝트를 생성해주고 Firestore Database를 클릭해주자

- 클릭하면 이런 화면이 나옴

- 데이터베이스 만들기를 클릭

프로덕션 모드에서 시작

- 그러면 이런 화면이 뜬다 ! 여기서 규칙을 수정해주자

기본 파이어베이스에서 제공해주는 코드를 해석해보면
→ 모든 경로에 대해 읽기와 쓰기 전부 금지! 안전하긴 하지만 아무것도 하지 못하기 때문에 수정을 해줘야한다.
📬 조회수 측정은 가능할 수 있도록
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /views/{slug} {
allow read: if true;
allow update: if
request.resource.data.keys().hasOnly(['count']) &&
request.resource.data.count is int &&
request.resource.data.count > resource.data.count;
allow create: if
request.resource.data.keys().hasOnly(['count']) &&
request.resource.data.count == 1;
}
match /{document=**} {
allow read, write: if false;
}
}
}
이렇게 수정하고 게시를 눌러줘서 반영해줬다 !
- Firebase 프로젝트 클릭하면 상단 가운데 아이콘 중
</>(웹 앱 추가) 클릭해주고 하라는대로 해주면
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
};
이런 설정객체들을 알려주는데
firebase.js 폴더를 만들어줘서 넣어줬다.
import { initializeApp, getApps } from "firebase/app";
import { getAnalytics, isSupported } from "firebase/analytics";
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
};
const app =
getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];
let analytics = null;
if (typeof window !== "undefined") {
isSupported().then((yes) => {
if (yes) {
analytics = getAnalytics(app);
}
});
}
export { app };
이렇게 하면 firebase 준비는 끝났다 !!!!!
이제 vscode에서 설정해보자
incrementView.js
import { db } from "./firebase.js";
import {
collection,
getDocs,
doc,
getDoc,
setDoc,
updateDoc,
increment,
} from "firebase/firestore";
export async function incrementViewCount(slug) {
const ref = doc(db, "views", slug);
const snap = await getDoc(ref);
if (snap.exists()) {
await updateDoc(ref, {
count: increment(1),
});
} else {
await setDoc(ref, {
count: 1,
});
}
}
export async function getViewCount(slug) {
const ref = doc(db, "views", slug);
const snap = await getDoc(ref);
return snap.exists() ? snap.data().count : 0;
}
export async function getTotalViews() {
const snapshot = await getDocs(collection(db, "views"));
let total = 0;
snapshot.forEach((doc) => {
total += doc.data().count || 0;
});
return total;
}
TotalView.js
import { useEffect, useState } from "react";
import { getTotalViews } from "../../lib/incrementView";
export default function TotalView() {
const [total, setTotal] = useState(0);
useEffect(() => {
getTotalViews()
.then(setTotal)
.catch(() => setTotal(0));
}, []);
return (
<div className="text-right sm:text-sm text-xs text-gray-600 dark:text-gray-400">
조회수 | <span className="font-semibold">{total.toLocaleString()}회</span>
</div>
);
}
만든 컴포넌트를 _app.js에 넣어줬다

이렇게 틀은 만들었고 아직 만든 페이지가 없어서 slug를 홈에만 넣어주려고 한다.
index.js
import { useEffect } from "react";
import { incrementViewCount } from "../../lib/incrementView";
export default function Home() {
useEffect(() => {
incrementViewCount("home");
}, []);
return <div className="max-w-[940px] mx-auto"></div>;
}
설정 완료 ~~~ ! 🤭
아직은 배포를 안 해서 조회수는 증가가 안되지만 기능 자체는 잘 붙여서 뿌듯하다.
역시 파이어베이스는 프엔한테 최고다…🙌🏻

![[React] 클라이언트에서 이미지를 압축해보자](https://cdn.hashnode.com/res/hashnode/image/upload/v1759903597964/227ea5dc-8ff1-4999-9869-1bceb71b210a.png)
![[책 추천] 프론트엔드 개발자라면 반드시 알아야 할 '웹 접근성' 이야기](https://cdn.hashnode.com/res/hashnode/image/upload/v1753777028409/0438e77e-a609-48d8-989a-68191214a5b1.png)
![[Next.js] 나만의 학습 블로그 만들기#3-다국어 지원 (Feat.next-i18next)](https://cdn.hashnode.com/res/hashnode/image/upload/v1752472189546/a25d48d1-715a-4c90-a530-7dded2981fe7.png)
![[Next.js] 나만의 학습 블로그 만들기#4 - 댓글 기능(Feat. Giscus)](https://cdn.hashnode.com/res/hashnode/image/upload/v1752477512377/e1e868c0-6968-49f0-8fc5-91083b01ef79.png)
![[React] React + localStorage로 하루에 한 번만 보이는 팝업 만들기](https://cdn.hashnode.com/res/hashnode/image/upload/v1751525304623/4d143f95-eeac-42fb-9a95-b21d12d2e476.png)