next getServerSideProps로 게시판 최신화데이터 불러오고 만들기

미마모코딩·2022년 11월 18일
0

팀 프로젝트 경험

목록 보기
3/6
post-thumbnail
<script>
import DetailPage from "@containers/main/board/detail/DetailPage"
import { BoardItem } from "@models/board"
import { getboardById } from "@services/board"

import { GetServerSidePropsContext } from "next"

import React from "react"

const Index = ({
  data,
  board_name,
  board_id
}: {
  data: BoardItem | undefined
  board_name: string
  board_id: string
}) => {
  return <DetailPage data={data} board_name={board_name} board_id={board_id}></DetailPage>
}

export default Index

export async function getServerSideProps(context: GetServerSidePropsContext) {
  // "/commnity/boardName/id"
  const splitedPath = context.resolvedUrl.split("/")
  const splitedPathLength = splitedPath.length
  const board_name = splitedPath[2]
  const board_id = splitedPath[splitedPathLength - 1]

  if (!board_id || !board_name) throw new Error("board_id, board_name is missing")

  const data = await getboardById({ board_id, board_name })
  if (!data) return
  return {
    props: { data: JSON.parse(JSON.stringify(data)), board_name, board_id }
  }
}
</script>

먼저 위와같이 게시판을 보여줄땐 url로 요청이 들어오는 순간 최신화된 데이터를 사용자에게 제공해야한다.

next를 사용하면서 이런 로직에 대한 충분한 고민이 필요하다는것을 실전에서야 느꼈다.

위와같이 사용자에게 요청받은 url로 원하는 부분을 추출하고 , DetailPage로 data props를 넘겨줬다.

<script>
import React from "react"
import { BoardItem } from "@models/board"
// eslint-disable-next-line no-unused-vars
import { deleteBoard, getboardById, updateBoard } from "@services/board"
// deleteBoard
import { addComment, deleteComment, updateComment } from "@services/comment"
import { addReComment, deleteReComment } from "@services/recomment"

import Link from "next/link"
import { useRouter } from "next/router"
import { useRef, useState } from "react"
import { useUserState } from "src/10.context/AuthUserContext"
import BoardCommentItem from "src/11.board_comment_item/Board_comment_item"

import * as S from "../DetailPage.style"

const DetailPage = ({
  data,
  board_name,
  board_id
}: {
  data: BoardItem | undefined
  board_name: string
  board_id: string
}) => {
  const { token, user } = useUserState()
  const router = useRouter()
  const [recommentInputVisible, setRecommentInputVisible] = useState<boolean>(false)
  const [commentModify, setCommentModify] = useState<boolean>(false)
  const [content, setContent] = useState("")

  const boardCommentRef = useRef<{
    board_name: string
    board_id: string
    comment_author_name: string
  }>({
    board_name,
    board_id,
    comment_author_name: ""
  })
  if (!data) throw new Error("no data")
  const isAuthor = data.author == user?.uid

  const boardRecommentRef = useRef<{
    content: string
    board_name: string
    board_id: string
  }>({
    content: "",
    board_name,
    board_id
  })

  return (
    <S.Wrapper>
      <div className="board_title_author_name_container">
        <h3 className="board_content_title">{data.title}</h3>
        <span className="board_content_author_name">{data.board_author_name}</span>
        <span className="board_created_at">작성일자:</span>
      </div>

      <div className="board_content_container">
        <p className="board_content">{data.content}</p>
      </div>
      <div className="comment_container">
        <div className="board_delete_update_box">
          {isAuthor ? (
            <span className="board_delete_btn" onClick={() => handleDeleteBoard()}>
              글 삭제하기
            </span>
          ) : null}
          <Link href={`/community/${board_name}/modify/${data.board_id}`}>
            <a>
              {isAuthor ? (
                <span className="board_update_btn" onClick={() => handleUpdateBoard()}>
                  글 수정하기
                </span>
              ) : null}
            </a>
          </Link>
        </div>
        <div className="comment_box">
          <h3>댓글</h3>

          <input
            onChange={(e) => setContent(e.target.value)} //content value = "안녕하세요"
            className="comment_input_area"
            type="text"
            maxLength={400}
            value={content}
          />
          <button
            className="comment_submit_btn"
            onClick={() => {
              handleCommentSubmit()
            }}
          >
            등록
          </button>
        </div>
        <div className="comment_board">
          <ul>
            {data.comments?.map((comment, i) => (
              <>
                <BoardCommentItem
                  board_name={board_name}
                  board_id={board_id}
                  handleModifyComment={handleModifyComment}
                  setCommentModify={setCommentModify}
                  commentModify={commentModify}
                  boardRecommentRef={boardRecommentRef}
                  setRecommentInputVisible={setRecommentInputVisible}
                  recommentInputVisible={recommentInputVisible}
                  handleDeleteComment={handleDeleteComment}
                  handleDeleteRecomment={handleDeleteRecomment}
                  handleAddRecomment={handleAddRecomment}
                  comment={comment}
                  i={i}
                  user={user}
                ></BoardCommentItem>
              </>
            ))}
          </ul>
        </div>
      </div>
    </S.Wrapper>
  )

  ///
  function inputValueReset() {
    setContent("")
  }

  function handleCommentSubmit() {
    console.log("!")

    const { board_name, board_id } = boardCommentRef.current
    if (!token || !user) throw new Error("token or user is missing")
    addComment({ token, user }, { content, board_name, board_id })
      .then(() => router.push(router.asPath))
      .then(() => inputValueReset())
  }

  function handleDeleteBoard() {
    if (!token || !user) throw new Error("token or user is missing")
    const deleteReCommentAgree = confirm("정말 삭제하시겠습니까?")
    if (deleteReCommentAgree) {
      deleteBoard(
        { token, user },
        {
          board_name,
          board_id
        }
      ).then(() => router.push(`/community/${board_name}`))
    } else return
  }
  function handleUpdateBoard() {
    if (!token || !user) throw new Error("token or user 2is missing")
    if (!data) throw new Error("no data")

    updateBoard(
      { token, user },
      {
        board_name,
        title: data.title,
        content: data.content,
        board_id,
        is_secret: data?.is_secret || null,
        is_notice: data?.is_notice || null,
        secret_number: data?.secret_number || ""
      }
    )
  }

  function handleDeleteComment(comment_author_id: string, comment_id: string) {
    if (!token || !user) throw new Error("token or user is missing")
    const deleteCommentAgree = confirm("정말 삭제하시겠습니까?")
    if (deleteCommentAgree) {
      deleteComment(
        { token, user },
        {
          board_name,
          board_id,
          comment_id,
          comment_author_id
        }
      ).then(() => router.push(router.asPath))
    } else return
  }

  function handleModifyComment({
    content,
    board_name,
    board_id,
    comment_id,
    comment_author_id
  }: {
    content: string
    board_name: string
    board_id: string
    comment_id: string
    comment_author_id: string
  }) {
    if (!token || !user) throw new Error("token or user is missing")
    console.log(board_id)
    updateComment(
      { token, user },
      {
        content,
        board_name,
        board_id,
        comment_id,
        comment_author_id
      }
    ).then(() => router.push(router.asPath))
  }

  //대댓글 작성
  function handleAddRecomment(comment_id: string) {
    if (!token || !user) throw new Error("token or user is missing")
    const { content, board_name, board_id } = boardRecommentRef.current
    addReComment(
      { token, user },
      {
        content,
        board_name,
        board_id,
        comment_id
      }
    ).then(() => router.push(router.asPath))
    setRecommentInputVisible(false)
  }
  //대댓글 삭제
  function handleDeleteRecomment(comment_id: string, re_comment_id: string) {
    if (!token || !user) throw new Error("token or user is missing")
    const deleteReCommentAgree = confirm("정말 삭제하시겠습니까?")
    if (deleteReCommentAgree) {
      deleteReComment(
        { token, user },
        {
          board_name,
          board_id,
          comment_id,
          re_comment_id
        }
      ).then(() => router.push(router.asPath))
    } else return
  }
}
</script>
export default DetailPage

먼저 useUserState를 통해 사용자의 대한 데이터를 받아오고 대댓글이 보이는 조건 ,
댓글삭제조건 ,댓글 수정 조건 의 대한 모든 분기처리를 하는데 시간이 꽤 오래걸렸던것같다.

먼저 댓글삭제하기 버튼이 보이는 조건자체가 내가 쓴 댓글일때만 이기때문에

const isAuthor = data.author == user?.uid

를 통해서 변수로 담아두고 수정 삭제 , 대댓글삭제 에 재사용을 할 수 있게 사용했다.

또한 함수를 function으로 가장 아래로 둔 것은 호이스팅으로 인해 상태가 끌어올려져 동작은 똑같이 하기때문에 조금 더 가독성이 좋게 만들었다 .

const () => {} <<이런형식으로 하면 당연히 선언과 초기화단계가 일치하지 않기에 function 키워드만 가능하다 .

                       컴포넌트의 구조 설계
                              
                daetailPage getServerSideProps전달
                             |
                   daetail Component (getServerSideProps사용)
                             |
                BoardCommentItem(getServerSideProps사용)
                             |
                  BoardRecommentItem
                             
 
 
 
 
 

위와같이 Detail page를 구성하고 재사용성을 높였다 . 중복되고 반복되는 부분의 스타일링은
globalCss에서 다루고 styled Component를 사용했다.

0개의 댓글