평소 메모장을 사용할 때 편리했던 기능 중에 하나인 '북마크 기능'을
현재 리팩토링을 진행하고 있는 게시판 프로젝트에 적용해보고 싶었다
북마크 버튼을 통해 게시글을 북마크하고,
북마크된 게시글을 최상단에서 볼 수 있는 기능을 구현하고자 한다.
구현 화면
목차
- 북마크 기능 구현 단계
- MongoDB를 활용한 API 세팅
- (Next.js App Router 를 사용한) UI 세팅
📌 북마크 기능 구현 단계
북마크 기능을 구현하기 위해서는 아래 단계를 거치면 된다.
- 데이터베이스 내 게시글 데이터에 북마크 관련 필드를 추가한다
- 북마크 여부를 저장하는 API 를 세팅한다
- UI 를 세팅한다 (→ 북마크 버튼, 북마크된 게시글이 최상단에 위치할 수 있도록 재정렬)
📌 MongoDB 를 활용한 API 세팅
게시글 북마크 관련 필드값은 isBookmarked
로 지정했다.
api/board/bookmark-article/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { connectDB } from '@util/database'
import { ObjectId } from 'mongodb'
export async function POST(req: NextRequest) {
try {
const db = (await connectDB).db('board')
const body = await req.json()
await db
.collection('article')
.updateOne(
{ _id: new ObjectId(body.id as string) },
{ $set: { isBookmarked: body.isBookmarked } },
)
return NextResponse.json({ data: true })
} catch (e) {
return NextResponse.json(
{ message: '북마크 설정 중 오류가 발생했습니다.' },
{ status: 500 },
)
}
}
- App Router ver. API 로직으로, POST 함수를 생성한다
- body 로 게시글 id 값과 북마크 여부를 나타내는 isBookmarked 값을 받는다
updateOne
: 해당하는 id 값을 가진 게시글을 찾아, 북마크 여부를 바꾼다$set
연산자 : 필드 값을 지정된 값으로 바꾼다
- 응답값은 boolean 형태로 주어, 요청이 성공했는지 실패했는지 판단할 수 있도록 하였다
📌 UI 세팅 (feat. App Router)
BookmarkBtn.tsx
'use client'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faThumbTack } from '@fortawesome/free-solid-svg-icons'
export default function BookmarkBtn({
selected,
bookmarked,
}: {
selected: string
bookmarked: boolean
}) {
const handleBookmarkArticle = async () => {
try {
const response = await fetch('/api/board/bookmark-article', {
method: 'POST',
body: JSON.stringify({
id: selected,
isBookmarked: !bookmarked,
}),
})
const data = await response.json()
if (response.status === 200) {
window.location.reload()
} else if (response.status === 500) {
alert(data.message)
}
} catch (e) {
console.error(e)
}
}
return (
<div className="bookmark-wrapper" onClick={handleBookmarkArticle}>
<FontAwesomeIcon
icon={faThumbTack}
className={`article-icon ${bookmarked && 'bookmarked'}`}
/>
</div>
)
}
'use client'
: click event 가 일어나야 하기 때문에 client component 로 생성한다- 해당하는 게시글의 id 값과 bookmark 여부를 알 수 있는 값을 props 로 전달한다
- 북마크 버튼 클릭 시, id 값과 기존 bookmark 여부의 반대되는 값을 body 에 실어 보낸다
- API 요청이 성공했으면 (= 북마크 여부 저장을 성공했으면) 페이지를 새로고침한다
- 실패했으면 에러 메시지를 띄운다
- bookmark 여부에 따른 style 은 className 을 통해 주었다.
API 요청 성공 - 페이지 새로고침 시
북마크된 게시글이 최상단에 위치하도록 하려면 아래와 같이 데이터를 불러오면 된다
app/page.tsx
import ArticleItem from '@components/board/ArticleItem'
import { connectDB } from '@util/database'
import { ArticleItemFlag } from '@util/interface'
export default async function Home() {
const db = (await connectDB).db('board')
const articles = await db
.collection<ArticleItemFlag>('article')
.find()
.sort({ isBookmarked: -1, regDate: -1 })
.toArray()
return <ArticleItem articles={articles} />
}
- sort() 사용
isBookmarked: -1
: 북마크된 게시글(isBookmarked가 true)이 가장 먼저 나오도록 내림차순으로 정렬regDate: -1
: 같은 북마크 상태 내에서, 게시물 작성일(regDate)을 기준으로 최신순으로 정렬
게시판 프로젝트 바로가기👇
728x90
댓글