Next.js - URL 정리하기

chu·2021년 4월 20일
0

현재 개인 프로젝트 작업 중... 포스트를 올리지 못하고 있다..
작업 중에 정말 막히고, 막히고 또 막힌 부분들이 있었다. 물론 해결하면서 진행했지만!

그 해결했던 것 중 하나만 정리하고 다시 작업 진행하려고 한다.


현재 벨로그 st.. 프로젝트를 만들고 있다! 물론 ㅋㅋ 비교할 수는 없겠지만 그런 느낌의 프로젝트이다. 포트폴리오에 넣을 프로젝트!

자세한 사항은 생략하려고 한다. (너무 길어져...😇)

작업 소개

첫번째 문제

여러 포스트카드가 노출되는 페이지에서 하나의 포스트카드를 클릭 시 해당되는 포스트 페이지가 나오는 방법을 구현하고 싶었다.

우선 Next를 사용하고 있었기 때문에 Next에서 제공되는 Link를 사용했다.

import Link from 'next/link';

// item은 각 포스트의 데이터를 갖고 있음
const PostCardLayout = ({ item }) => {
  // ...
  return (
    // ...
    <Link
      href={{
        pathname: '/[pagename]/[id]',
        query: { postId: item.id },
      }}
      as={`/${item.User.nickname}/${item.title}`}
      >
      <a className="title">{item.title}</a>
    </Link>
  )
}

위 처럼 href에는 해당 경로에 맞는 pathname을 설정해주고, query로 필요한 값을
전달할거다. as는 실제 주소창에 나오는 부분이기도 하고, 데이터를 갖고 있다.

하지만 이대로 보내게 될 경우 item.title에는 실제 제목을 그대로 갖고 있다. 이게 무슨 뜻이냐~

포스트 제목 - Next.js 배워볼까?!

위 제목을 주소로 보내면 어떻게 될까?

http://localhost:/3000/nickname/Next.js%20배워볼까?!

공백에는 %20이 생기게되고, 특수문자도 그대로 나타난다. 너무 보기 안좋다!
그래서 정규표현식으로 공백과 특수문자를 모두 -로 바꾸기로 했다.

import Link from 'next/link';

// item은 각 포스트의 데이터를 갖고 있음
const PostCardLayout = ({ item }) => {
  // ...
  
  // 정규표현식 - url 타이틀 특수문자 및 공백 '-'변환 후 마지막 '-'은 제거
  const regex = /[\s\{\}\[\]\/?.,;:|\)*~`!^\-_+<>@\#$%&\\\=\(\'\"]+/g;
  const regex2 = item.title.replace(regex, '-');
  const title = regex2.replace(/-$/, '');
  
  return (
    // ...
    <Link
      href={{
        pathname: '/[pagename]/[id]',
        query: { postId: item.id },
      }}
      as={`/${item.User.nickname}/${title}`}
      >
      <a className="title">{item.title}</a>
    </Link>
  )
}

사실 아직 정규표현식에 대해서 많은 지식이 없다... 여기저기 정리된 글을 보며 만들었다.
그래서 코드가 더럽다😊 두번을 변환해서 최종 title을 as에 넣어준다.

그렇게 바뀐 주소?

http://localhost:3000/Dev01/Next-js-배워볼까

너무 깔끔하게 변해서 주소에 출력이 된다. 그럼 저 주소로 서버에 요청을 하면 된다.
이번 작업에서는 Next를 사용한 만큼 SSR로 작업을 했다.

export const getServerSideProps = wrapper.getServerSideProps(async (context) => {
  // ... 
  await context.store.dispatch(
    // 하나의 포스트 불러오기
    singlePostLoad({
      nickname: context.params.pagename, // pathname 1
      title: context.params.id, // pathname 2
    }),
  );
});

SSR로 처리 할 시 프론트서버에서 디스패치를 실행 후, 백 서버에 요청이 들어간다.
그리고 다시 백에서 응답을 받고, 데이터가 채워진 채로 브라우저에 나타나게 된다.

singlePostLoad action이 어떻게 요청되는지는 생략... 시간이 없어...
간단하게 저 context.params에서 주소가 갖고 있는 값을 읽어온다.
읽어온 값을 디스패치해서 백 서버에 요청을 보낸다. 이렇게만 해도 너무 잘되는걸~?

두번째 문제

새로고침 및 새 페이지에서 주소를 치면 Not Found나 백 서버에서 응답처리를 못해주는 경험을 맞이한다. 주소만으로 공유도 하는 상황도 필요할텐데 그게 안되면 이건 완전히 잘못된 기획이다.
그래서 추가적으로 백에도 작업을 해줬다.

그럼 백에서 해당 라우터를 확인해보자.

// 게시글 하나만 불러오기 - GET /post/유저닉네임/포스트타이틀
router.get('/:nickname/:title', async (req, res, next) => {
  try {
    const user = await User.findOne({
      where: { nickname: req.params.nickname },
    });
    if (!user) {
      return res.status(400).send('존재하지 않는 계정입니다.');
    }

    // 닉네임으로 유저의 포스트 모두 조회
    const posts = await Post.findAll({
      where: { UserId: user.id },
      attributes: ['title', 'id'],
    });
    // 조회한 포스트 모두 정규표현식으로 변환
    const regex = /[\s\{\}\[\]\/?.,;:|\)*~`!^\-_+<>@\#$%&\\\=\(\'\"]+/g;
    const a = posts.map((item) => {
      return {title: item.title.replace(regex, '-'), id: item.id}
    });
    const b = a.map((item) => {
      return {title: item.title.replace(/-$/, ''), id: item.id}
    });
    // 변환을 거친 포스트 제목과 req.params.title과 비교
    const find = b.filter((item) => item.title === req.params.title);

    // 비교해서 나온 결과물의 id로 DB 조회
    const post = await Post.findOne({
      where: { id: find[0].id },
      include: [{
        model: User,
        attributes: ['id', 'nickname'],
      }, {
        model: Comment,
        include: [{
          model: User,
          attributes: ['id', 'nickname'],
        }],
      }, {
        model: User,
        as: 'Likers',
        attributes: ['id'],
      }],
    });
    res.status(200).json(post);
  } catch(error) {
    console.error(error);
    next(error);
  }
});

뭔가 굉장해 엄청나 급으로 더러운 코드를 보여준다 ㅋㅋ... (좋은 방법있으면 피드백 좀 ㅜ)
백에서는 저장된 DB의 user 테이블에서 nickname을 조회한다. nickname이 존재한다면
그 nickname의 id를 가져온다.

가져온 id로 post 테이블에서 where로 조건 조회를 통해 해당 id가 작성한 포스트를 모두
가져온다.

그 포스트들을 여러 정규표현식 변환을 통해서 최초에 보내준 주소의 포스트 제목을 비교하여,
최종 검색 된 포스트를 응답해주는 방식이다.

사실 이 부분을 작업하면서 백에서 이렇게까지 해당 유저의 포스트를 전부 불러와서 정규표현식을 하고 뭐하고~ 솔직히 이 방법은 정말 아닌 생각이 들긴하다... 하지만 어찌해야할까... 이거 때매 어제 하루를 날리고, 금일 오전도 날려서 일단 이렇게 진행을 하려고 한다.

이렇게 올리는 이유는 더 좋은 방법이나 피드백을 받을 수 있을까? 싶어서도 있긴합니다...

profile
한 걸음 한걸음 / 현재는 알고리즘 공부 중!

0개의 댓글