7. 팀 별 게시글 목록 / 게시글 상세 페이지 구현

박준혁·2023년 6월 6일
0
post-thumbnail

앞선 과정에서는 게시글의 전체 목록을 확인하도록 게시글 메인 페이지를 제작했는데 팀 별 게시글의 목록을 확인할 수 있는 페이지와 게시글을 눌러 상세 페이지에서 확인할 수 있도록 확인할 수 있는 페이지를 구현하고자 한다.

팀 별 게시글 목록

팀 별 게시글 목록에서는 TeamNavBar의 팀 명을 눌렀을 때 해당 팀의 게시글을 확인할 수 있는 링크인 '/post/(팀 기수)th(팀 번호)'로 이동하게 된다. 해당 경로에서의 페이지를 구현하는 과정이다. 전체적으로 게시글 메인 페이지와 구성은 동일하고, 게시글의 목록만 다르게 표현된다.

Dynamic Routing

먼저 이를 구현하기 위해서는 Next.js에서 제공하는 Dynamic Routing의 개념을 알아야 하는데, 앞서 구현했던 것처럼 Next.js에서는 Routing 기능을 자동으로 제공한다. 특정 이름의 폴더를 제작하고, 해당 폴더 내 page.js를 이용해 사이트를 제작할 수 있다.
Dynamic Routing은 정의된 주소가 아닌 동적인 라우팅을 이용할 때 사용한다. 폴더의 이름을 대괄호 내부([])에 사용하면, 괄호 내부에 사용된 인자를 props로 저장할 수 있다. 구체적인 사용 방식은 아래에서 확인할 수 있다.

Next.js Dynamic Routing Document

구현 코드

해당 코드는 Dynamic Routing 방식을 사용하여 구현하였다. 기존 post 폴더 내부에 [team]이라는 폴더를 만들어 page.js를 생성하였다. 만약 '/post/8th1'과 같은 주소로 이동하면 props.params.team에 8th1라는 값을 전달한다. 따라서 th를 기준으로 앞에는 팀의 기수, 뒤에는 팀의 번호로 나뉘어서 전달되는 방식이다.
코드를 살펴보면 props에 [team] 자리의 인자가 전달되므로, 팀의 기수와 번호를 구분하기 위해 'th'를 기준으로 split을 이용해 semester와 team을 나누어 저장한다. 해당 값을 바탕으로 db의 post collection에서 해당 semester와 team이 일치하는 정보들을 찾아 result에 저장하고, 해당 result를 바탕으로 메인 페이지와 동일하게 ListItem 함수를 이용해 게시글을 표현하였다.

// /post/[team]/page.js
export default async function teampage(props){
    const [semester, team] = props.params.team.split('th')
    const db = (await connectDB).db('vessweb');
    let result = await db.collection('post').find({"semester":semester,"team":team}).toArray();
    result = result.reverse();
    return(
        <div>
            <ListItem result={result} />
        </div>
    )
}

구현 결과

게시글 상세페이지 구현

게시글을 누르면 상세페이지로 들어가게 되고, 해당 페이지에서 게시글의 정보들을 열람할 수 있게 된다. 동일하게 Dynamic Routing 방식을 사용하고, /post/[team]/[id] 경로로 들어가게 되면 확인할 수 있다. [id]에는 MongoDB에서 지정된 Object id 값이 저장되고, 해당 id와 일치하는 게시글을 찾아 화면에 출력한다.

구현 코드

DB와 연결해서 findOne 함수를 통해 id가 일치하는 결과를 찾아 result에 저장한다. 해당 게시글의 First Posted 정보와 Recently Posted 정보를 받아와 출력하고, 저자, 팀명, 제목, 글 내용을 게시글에서 받아와 출력한다. readOnly를 추가해 사용자가 바꿀 수 없도록 설정한다.

// /post/[team]/[id]/page.js
export default async function Detail (props){
    const db = (await connectDB).db('vessweb');
    let result = await db.collection('post').findOne({_id:new ObjectId(props.params.id)})
    let session = await getServerSession(authOptions)
    return (
        <div>
            <h1>View Post Detail</h1>
            <div>
                <div>
                    <span>First Posted : {result.FirstAuthor}, {result.firstCreated}</span>
                    <span>Recently Posted : {result.LastAuthor}, {result.lastModified}</span>
                </div>
            </div>
            <div>
                    <div>
                        <span>Author</span>
                        <span>Team Name</span>
                        <span>Title</span>
                        <span>Content</span>
                    </div>
                    <div>
                        <input name="author" readOnly defaultValue={result.FirstAuthor}/><br />
                        <input name="teamname" value={result.teamname} readOnly/><br />
                        <input name="title" placeholder="글 제목" readOnly defaultValue={result.title}/><br />
                        <textarea name="content" placeholder="글 내용" readOnly rows="15" cols="100"  defaultValue={result.content}/><br />
                    </div>
            </div>
        </div>
    )
}

구현 결과

0개의 댓글