본문 바로가기
nextjs

비동기 데이터로 jsx 구성 시 최적화 및 예외 처리

by spare8433 2023. 6. 23.
  • 2023.06.27 오류 발견 및 내용 업데이트

 


PART 1. sequlize findOne 메서드의 null return

 

설명

 

개발 환경

  • back : express + sequlize + ts
  • from : nextjs + redux toolkit + ts

 

sequlizefindOne 메서드를 통해 데이터베이스의 내용을 조회하는 기능을 구현했다.

 

try-catch 문안에서 조회 성공 시 2xx 번대 실패 시 4xx, 5xx 번대 상태코드로 반환하여 redux toolkit 기능들을 활용 비동기 작업을 처리하고 있는 와중 잘못된 요청에도 데이터 없이 화면이 나타나고 redux 의 state, api 요청 역시 에러관련 내용이 없었고 값은 있어야 할 state 의 값이 null 인 이상한 상황이 나왔다.

 

알고 보니 sequlize 의 findOne 메서드는 조회한 결과가 없을 경우 null 을 반환하기 때문에 try-catch 문안에서 오류로써 예외처리되지 않으며 정상적으로 2xx 번대 상태로 값이 넘어온 것

 

그래서 아래와 같이 값이 존재하지 않을 때 404 코드로 오류가 있음을 알려 reducer 가 오류임을 인지하고 예외처리를 할 수 있게 수정했다.

 

코드

// sequlize 모델 형식의 BalanceDebatePost
import BalanceDebatePost from  "@models/balanceDebatePost";

router.get("", async (req, res, next) => {
  try {
    const balanceDebatePostData = await BalanceDebatePost.findOne({
      ...
    });

    // 조회한 데이터가 존재하지 않을 때
    if (!balanceDebatePostData)
      res.status(404).json({ message: "존재하지 않는 게시글입니다" });

    // 정상적으로 조회한 데이터가 있을 때
    res.status(200).json(balanceDebatePostData);
  } catch (error) {
    // 에러 발생 시
    next(error);
  }
});



PART 2. 비동기 데이터로 jsx 구성 예외 처리 및 최적화

 

설명

 

위 문제를 겪으면서 다른 수정할 점이 있음을 느꼈다.

 

ts 환경에서 비동기 데이터를 활용하여 jsx를 구성한다면 비동기 데이터의 타입이 null, undefined 등 타입을 확정 지을 수 없으므로 eslint 환경에 따라 오류를 띄울 것이며 작업하는 입장에서도 명확하지 않다.

 

api 서버에서 오류는 아니지만 비정상적인 데이터가 들어올 수 있고 이 경우 api 요청, 응답, 저장하는 과정에서도 오류를 인지하지 못할 수 있으며 웹 서버에서는 비정상적인 데이터임에도 jsx 를 구성하는 소요가 생긴다



해결 방법

 

개인적인 방법이고 참고만 하는 것이 적절해보임

1. API 요청 상황에서 예외 처리

  • SSR 환경에서 랜더링 이전에 진행되는 api 요청에서 오류 발생 시 302 코드 반환하여 바로 리다이렉트 시켜 불필요한 랜더링을 사전 차단

 

코드

 

import { getIssueDebatePost } from "@store/slices/issueDebatePost" // API 요청 reducer
import { wrapper } from "@store/store"    // next-redux-wrapper 내용

// next-redux-wrapper SSR 구현 메서드
export const getServerSideProps = wrapper.getServerSideProps(
  (store) =>
    async ({ req, res, query }) => {
      const { pid } = query

      if (pid) {
        try {
          // dispatch
          await store.dispatch(getIssueDebatePost(pid as string)).unwrap()
        } catch (error) {
          console.log(error)
          // 리다이렉션
          res.writeHead(302, { Location: '/' })
          res.end()
        }
      }
      return { props: {} }
    },
)



2. 컴포넌트 내에서 예외처리

 

  • A. 컴포넌트 내에서 특정 데이터가 없으면 빈 태그를 반환하게 구성하고 useEffect 를 통해 마찬가지로 특정 데이터가 없으면 페이지 이동 시키는 코드를 구성하여 불필요하게 jsx 구성하지 않는다.
  • 위 방법의 치명적이 오류가 있어 업데이트 하려함 - 2023.06.27
    • 뒤로가기 버튼을 눌러 페이지가 이동되는 중에  useEffect 의존성 배열안에 있는 postData 의 데이터를 인식해 페이지가 이동되는 오류가 존재함 (단순히 if 안에 위치해도 안에 내용이 실행됨)
    • 결론적으로 postData 의 값을 기준으로 페이지 이동을 시킨다면 불필요한 페이지 이동이 일어남
    • 개선된 방식을 찾아 업데이트 예정

 

코드(오류가있음)

 

import React, { useEffect } from 'react'
import { useAppSelector } from '@store/store'
import { useRouter } from 'next/router'

const IssuePostPage = () => {
  const router = useRouter()
  const postData = useAppSelector((state) => state.issueDebatePost.postData)

  // 초기 랜더링이후 데이터가 없다면 화면이동
  useEffect(() => {
    const isPostNull = async () => {
      if (!postData) router.push('/debate-forum')
    }
    isPostNull()
  }, [postData, router])

  // 데이터가 존재하지 않으면 빈 태그 반환
  if (!postData) return <></>

  // 데이터가 존재하면 일반적인 jsx 구성요소 반환
  return <p>jsx 구성요소</p>
}

export default IssuePostPage



  • B. 특정 데이터 상태에 따라 대체 콘텐츠를 반환하는 코드를 구성

 

import React from 'react'
import { useAppSelector } from '@store/store'

const IssuePostPage = () => {
  const { getPostError, postData } = useAppSelector((state) => state.issueDebatePost)

  // 오류 발생시
  if (getPostError || !postData) return <>오류 발생시 대체 jsx 구성요소</>

  // 데이터가 존재하면 일반적인 jsx 구성요소 반환
  return <>jsx 구성요소</>
}

export default IssuePostPage