visitors
46
일일 방문자 수

03월 11일 (화) 오후 17:38

Responsive image

URL 값을 읽어주는 useRoute

Created: 2023. 06. 07 07:55 오전
Updated: 2023. 06. 12 05:37 오전

주소에 따라 특정 컴포넌트로 변경하게 했지만, 아직 Notion API에 적용까지 하지 못하여 내용이 나오지 않고 있습니다. 이를 위해서 글의 id와 카테고리 값이 필요한데, 이를 URL에서 가져오는 방법에 대해 알아보겠습니다.

URL

url이란? Uniform Resource Locator의 약자로, 인터넷에서 특정 리소스(Resource)의 위치를 가리키는 문자열입니다. 리소스란, 웹 상에서 클라이언트가 요청한 정보를 의미합니다. 대표적으로 HTML, CSS, JavaScript, 이미지 등이 있습니다. 즉 URL은 웹 상에서 존재하는 정보들의 경로(위치)를 말합니다.

URL 구조

URL 구조는 크게 다음과 같이 구성되어있습니다.

  1. 프로토콜 (Protocol): 리소스에 접근하기 위한 규칙이라고 할 수 있습니다. URL에 사용되는 가장 일반적인 프로토콜은 HTTP와 HTTPS입니다. HTTP는 보안성이 낮은 반면, HTTPS는 보안성이 높습니다.
  1. 호스트 주소 (Host Address): 리소스가 위치한 서버의 주소를 의미합니다. 일반적으로 도메인 이름으로 사용됩니다. 도메인 이름은 IP 주소와 매핑되어 있으며, IP 주소를 입력해도 도메인 이름으로 리소스에 접근할 수 있습니다.
  1. 파일 경로 (File Path): 서버 내에서 리소스가 위치한 경로를 의미합니다. 파일 경로는 디렉토리와 파일 이름으로 구성되어 있으며, 슬래시 (/)로 구분됩니다.
  1. 쿼리스트링(Query String): URL에서 사용되는 파라미터(Parameter)의 일종입니다. 쿼리스트링은 URL의 끝에 ? 기호와 함께 전달되며, 여러 개의 파라미터들은 & 기호로 구분됩니다. 쿼리스트링을 사용하면 클라이언트가 서버에게 정보를 전달할 수 있습니다. 예를 들어, 검색 엔진에서 검색 결과 페이지를 보여줄 때, 검색어를 쿼리스트링으로 전달하여 검색 결과를 필터링할 수 있습니다.

만약 https://realmyspace.com/category/html 이라는 URL에 접속한다면, 해당 서버가 가진 서버의 /category/html 폴더에 위치한 index.html 파일을 요청하여 페이지를 보여주게됩니다.

      Q] html까지만 적었는데 왜 index.html을 가져오나요?
A] 서버는 폴더까지 적을 경우 특정 파일을 읽도록 설정되어있습니다. 보통은 index.html을 가져오며 default.html나 그 외에 다른 파일을 보도록 설정할 수 있습니다.
    

이번 시간에는 파일 경로 값을 읽어와서 글 목록과 내용을 가져와

useRoute

URL에 대한 정보는 VueRouter의 useRoute 함수를 통해 가져올 수 있습니다.

javascript
      import { useRoute } from "vue-router"

const route = useRoute();
    

PostList에 적용하기

이 내용을 PostList.vue에 추가해보겠습니다.

html
PostList.vue
      <script setup>
import { useRoute } from "vue-router";
import { ref, computed, onMounted } from "vue";
import { getPageTable } from "vue-notion";

const search = ref("");

const route = useRoute();
console.log(route);
// ...
</script>
    

그러면 route안에 다양한 반응형 객체들이 들어간 것을 볼 수 있는데요.

우리는 이 중 path라는 값을 사용해보겠습니다. path는 /category/html이란 값을 가지고 있습니다. 그럼 html이란 값도 가져올 수 있겠죠!

path의 값에서 /category/ 뒤의 값을 가져오는 방법은 다음과 같이 가능합니다.

html
      <script setup>
// ...

const route = useRoute();

// route.path ==> /category/html
// route.path.split('/') ==> ['', 'category', 'html']
// route.path.split('/').pop() ==> 'html'
const selectedCategory = route.path.split("/").pop();

// 기존의 props는 제거합니다.
// const props = defineProps(["selectedCategory"]);

// ...

// props.selectedCategory -> selectedCategory로 변경
const filteredList = computed(() => {
  if (search.value == "") {
    return postList.value[selectedCategory];
  } else {
    // ...
});
</script>
    

하지만 이럼에도 불구하고 글 목록이 나타나지 않을 것입니다. 왜냐하면 postList 값에는 대문자로 저장되어 있고, 우리의 selectedCategory 값은 소문자이기 때문입니다.

html
      postList = {
  HTML: [ ... ]
	CSS: [ ... ]
	Javascript: [ ... ]
}

selectedCategory = "html"
    

그래서 filteredList에서 값을 가져올 때 약간의 수정이 필요합니다.

javascript
PostList.vue
      const filteredList = computed(() => {
  if (search.value == "") {
    // category: "HTML" -> "CSS" -> "Javascript 순회
    for (const category in postList.value) {
      // category.toLowerCase() = "HTML" -> "html"
      // selectedCategory = "html"
      // 같은 경우 해당 리스트 반환
      if (category.toLowerCase() == selectedCategory) {
        return postList.value[category];
      }
    }
    // return postList.value[selectedCategory];
  } else {
  // ...
    

글 목록이 나타납니다!

하지만 CSS와 Javascript를 클릭해도 아무런 변화가 없습니다.

loading

기억하시나요 props.selectedCategory는 반응형이였다는 것을! 주소가 바뀜에 따라 selectedCategory 값도 반응해서 바뀌어야합니다. route값이 반응형 상태이기 때문에, computed를 사용할 수 있습니다.

html
PostList.vue
      <script setup>
// ...

// const selectedCategory = route.path.split("/").pop();
const selectedCategory = computed(() => route.path.split("/").pop());

// ...
const filteredList = computed(() => {
  // ...
      if (category.toLowerCase() == selectedCategory.value) {
        return postList.value[category];
      }
  // ...
});
</script>
    

이제야 제대로 바뀌네요! 하지만 아직 글을 클릭해도 주소가 바뀌지 않습니다. 이 것도 마저 바꿔볼게요!

loading

이전에 MenuBar에서 사용했던 RouterLink를 적용하면 됩니다.

html
PostList.vue
      <template>
<!-- ... -->
<ul>
  <li v-for="item in filteredList" :key="item.id">
    <!-- <button class="post" @click="$emit('click-post', item.id)">
      {{ item.title }}
    </button> -->
    <RouterLink class="post" :to="'/post/' + item.id">
      {{ item.title }}
    </RouterLink>
  </li>
</ul>
</template>
    

이제 주소도 바뀝니다!!

loading

다만 아무런 페이지가 나타나지 않는데요. 이는 우리가 router에서 이런 주소에 어떤 컴포넌트를 보여야할지 정하지 않았기 때문입니다. 개발자 도구에서 이런 경고문이 보일겁니다.

router/index.jsroutes 값에는 이런 경로들이 없었습니다.

javascript
router/index.js
      // ...
routes: [
  {
    path: "/category/html",
    component: PostList,
  },
  {
    path: "/category/css",
    component: PostList,
  },
  {
    path: "/category/javascript",
    component: PostList,
  },
  {
    path: "/post/1",
    component: PostContent,
  },
  {
    path: "/post/2",
    component: PostContent,
  },
  {
    path: "/post/3",
    component: PostContent,
  },
],
// ...
    

하지만 만약 이 주소에 대한 매칭을 따로 넣는다면 해당 글에 대한 페이지를 볼 수 있을겁니다.

javascript
      {
  path: "/post/8bc11312-00d8-4f68-b3b4-baa0c1c98e26",
  component: PostContent,
},
    

하지만 모든 페이지마다 이런 route 설정을 하는 것은 너무 번거롭습니다. 그래서 다음 글에서는 routes 설정을 좀 더 유연하게 할 수 있는 방법에 대해 다뤄보겠습니다.