5일차 - Routing, try & catch

류연찬·2022년 11월 11일
0

Codecamp FE07

목록 보기
6/39

라우터 객체와 라우팅

라우터(router) 객체란 페이지 이동과 관련된 가능을 가지고 있는 객체입니다.
이 객체를 사용해서 A페이지에서 B페이지로 이동할 때, "B 페이지로 라우팅한다"라고 합니다.

자주 사용하는 라우터(router) 객체 기능

import Router from 'next/router'

export default function Routing() {
    const handleClickPathname = () => {
        const pathname = Router.pathname
        alert(pathname)
    }

    const handleClickAsPath = () => {
        const asPath = Router.asPath
        alert(asPath)
    }

    const handleClickBack = () => {
        Router.back()
    }

    const handleClickPush = () => {
        Router.push('/')
    }

    const handleClickReload = () => {
        Router.reload()
    }

    const handleClickReplace = () => {
        Router.replace('/')
    }


    return (
      <>
        <button onClick={handleClickPathname}>현재 위치 주소: Router.pathname</button><br/>
        <button onClick={handleClickAsPath}>현재 위치 주소: Router.asPath</button><br/>
        <button onClick={handleClickBack}>뒤로가기 버튼: Router.back()</button><br/>
        <button onClick={handleClickPush}>현재 페이지에서, 다른 페이지로 이동: Router.push()</button><br/>
        <button onClick={handleClickReload}>새로고침: Router.reload()</button><br/>
        <button onClick={handleClickReplace}>현재 페이지 삭제 후, 다른 페이지로 이동: Router.replace()</button><br/>
      </>
    )
  }

더 많은 내용은 Next.js Router를 참고해 주세요.


정적 라우팅

/login 페이지는 누가 언제 접속해도 항상 로그인 페이지가 나옵니다.
이러한 페이지로 이동하는 것을 "정적 라우팅한다"라고 합니다.

동적 라우팅

게시판 상세보기와 같은 경우, 글 번호에 따라서 주소가 변경됩니다.
하지만 이러한 경우에는 게시글이 100개, 1000개가 넘어가게 되면 각각의 글 번호에 따라 페이지를 100개, 1000개씩 만들어 정적라우팅을 해주기는 어렵기 때문에 라우팅를 효과적으로 처리하기 위해서 동적 라우팅을 사용합니다.

/board/1 👉 1번 게시글 상세보기 페이지
/board/2 👉 2번 게시글 상세보기 페이지
/board/3 👉 3번 게시글 상세보기 페이지
/board/4 👉 4번 게시글 상세보기 페이지
...

이러한 페이지로 이동하는 것을 동적 라우팅한다라고 합니다.

Next.js에서는 동적 라우팅을 제공해줍니다.
폴더 구조는 pages 👉 boards 👉 [boardId] 👉 index.jsx(혹은 tsx) 이렇게 됩니다.
대괄호로 감싸준 폴더를 만들어주면 이동해주고자 하는 페이지 번호, 혹은 게시글 번호가 대괄호 안에 쓰여진 변수명에 담겨져 그 변수 안에 있는 데이터를 꺼내 조회할 수 있습니다.
이때, 대괄호 안에 쓰여지는 폴더 이름은 단순히 변수명이기 때문에 아무렇게 작성해도 상관없습니다.

실제로 router.query = { boardId: 1} 이런 형식으로 들어가게 되면서 자동으로 게시글 번호를 꺼내올 수 있습니다.

아래의 코드는 GraphQL을 통해 동적으로 게시글을 불러오는 예제입니다.

import { gql, useQuery } from "@apollo/client" 
import { useRouter } from "next/router"

// 여기서 'number'를 받고 query를 통해 fetchBoard 메소드를 실행시켜준다
const FETCH_BOARD = gql`
    query ($number: Int) {
        fetchBoard(number: $number) {
            number,
            writer,
            title,
            contents,
        }
    }
`

const staticRoutedPage = () => {

    const router = useRouter()

    const {data} = useQuery(FETCH_BOARD, {
        variables: {
						// router.query.number에서 number가 폴더 구조 중 []안에 들어간 변수명(number)
            number: Number(router.query.number)
        }
    })

    return (
        <div>
            <div>{router.query.number}번 게시글 이동이 완료되었습니다</div>
            <div>작성자: {data?.fetchBoard.writer}</div>
            <div>제목: {data ? data.fetchBoard.title : "불러오는중..."}</div>
            <div>내용: {data ? data.fetchBoard.contents : "불러오는중..."}</div>
        </div>
    )
}

export default staticRoutedPage

비동기 통신과 조건부 렌더링

JavaScript는 작성된 코드가 상단에서부터 순서대로 실행되기 때문에 데이터를 요청하고 응답을 받아오는 동안 화면에 그려질 데이터의 내용이 undefined이므로 첫 화면이 그려지는 시기에 데이터를 불러오면서 에러가 발생합니다.

이 부분이 효율적으로 실행되기 위해서 화면을 미리 그려놓고 데이터를 그려주기 위해서 조건부렌더링을 사용합니다.

조건부 렌더링에는 && 연산자, 삼향 연산자, 옵셔널 체이닝이 있습니다.

삼향 연산자

data는 동기적으로 받아와야하는 데이터입니다. 하지만 데이터가 오기 전에 이미 return 부분에서 rendering을 해주고 있기 때문에 삼향 연산자를 써서 데이터가 있을 때, 없을 때를 모두 적어줘야 합니다.

// data가 존재(true)하면 data.fetchProfile, 아니면(false) undefined
data ? data.fetchProfile : undefined

&& 연산자

&& 연산자는 데이터가 없을 경우 자동으로 undefined를 반환해줍니다.
앞의 값이 참일 경우에만 뒤의 값을 보여줬는데, 반대로 앞의 값이 거짓일 때 뒤의 값을 보여주는 경우는 Nullish Coalescing 연산자라고 부릅니다.

?? 연산자는 앞의 값이 빈 값(true)이면 뒤의 값을 보여주며 || 연산자는 앞의 값이 거짓(false)일 경우 뒤의 값을 보여줍니다.

data ?? data.fetchProfile

data || data.fetchProfile

옵셔널 체이닝 (Optional-Chaining)

optional-chaining이란 기존의 && 연산자를 쓰면서 길어졌던 코드를 더욱 간결하게 사용하는 연산자입니다.
optional-chainingES2020에서 나온 최신 문법입니다.

data?.fetchProfile

optional-chaining? 연산자 앞 객체의 참조가ㅣ undefined || null이라면 undefined를 리턴해줍니다.
위의 있는 삼향 연산자, && 연산자와 똑같은 기능을 하는 것입니다.

Apollo-Client로 GraphQL Query 실행

// graphql 요청에 필요한 도구 불러오기
import { useQuery, gql } from '@apollo/client'


// graphql 코드 생성
const FETCH_PROFILE = gql`
	query fetchProfile($name: String){
		fetchBoard(name: $name){
			title
			contents
		}
	}
`


// graphql 코드를 실행하기 위한 query 생성과 생성된 query의 실행(자동으로 실행됩니다)
const { data } = useQuery(FETCH_PROFILE)


// 최종 결과를 HTML에 보여주기
<div>
	이름: <span>{data && data.fetchProfile.name}</span>
	나이: <span>{data && data.fetchProfile.age}</span>
	학교: <span>{data && data.fetchProfile.school}</span>
</div>

템플릿 리터럴(Template Literal)
문자와 변수를 함께 쓸 수 있는 도구입니다. `${변수명}`으로 string과 변수를 연산자로 더해주지 않아도 가독성 좋게 코드를 작성할 수 있습니다.

GraphQL Mutation에 try/catch 적용

mutation이 항상 성공하는 것은 아닙니다.
Back-end 컴퓨터에 문제가 발생할 수도 있고, 내가 수정하려는 게시물이 갑자기 삭제가 되는 바람에 수정에 문제가 발생하는 등 여러가지 이유로 실패의 가능성이 존재합니다.

따라서, 성공에 대한 처리와 실패에 대한 처리를 나누어 작업을 해야합니다.

try {
		await createBoard({
				variables: {
						aaa: "훈이",
						bbb: "1234",
						ccc: "안녕하세요 훈이에요",
						ddd: "반갑습니다"
				}
		})

} catch(error) {
		alert(error.message)     // 경고창(실패했습니다.)  ==>  백엔드 개발자가 보내주는 실패 메시지
} finally {
	// 성공, 실패 여부와 상관없이 무조건 마지막에 실행되는 부분
	// 필요없다면 생략 가능
}

shorthand propety
객체를 정의할 때 객체의 key값과 value값이 같으면, 각각 표기하지 않고 한번만 표기하는 것을 의미합니다.

const result = await createUseditem({
        variables: {
          createUseditemInput: {
            name         // name: myName
            remarks      // remarks: myRemarks
            contents.    // contents: myContents
            },
          },
        },
      });

Apollo 디버깅 툴 (Apollo-Client-Devtools)
GraphQL을 사용하는데 도움을 주는 크롬 도구가 있습니다.
Apollo Client Devtools 설치하기

0개의 댓글