ㆍProject Diary/Vue (Roblox WebSite)
포스팅에서는 Vue.js를 이용해 외부 API를 호출하고, 비동기 통신을 통해 데이터를 가져와 화면에 표시하는 방법 기록
1. 비동기 통신을 통한 API 호출 (News.vue)
비동기 통신을 통해 외부 API를 호출하고 데이터를 가져오는 것이 이번 예제의 핵심입니다. 비동기 통신을 사용하면 데이터를 가져오는 동안 사용자 인터페이스가 블록되지 않아서 더욱 부드러운 사용자 경험을 제공합니다.
1-1 API 호출 코드
watch: {
countryCode: {
async handler(value, oldValue) {
try {
// fetch를 사용하여 외부 API 호출
let response = await fetch(
`https://newsapi.org/v2/top-headlines?country=${value}&pageSize=100&apiKey=개인키`
);
// API 호출 결과를 JSON으로 변환
let result = await response.json();
this.newsData = result.articles;
this.totalItems = result.totalResults;
this.pageNews = [];
this.headerNews = [];
console.log(value, oldValue);
// API에서 받아온 데이터로 페이지네이션 설정
for (
let i = 0;
i < Math.ceil(this.totalItems / this.itemPerPage);
i++
) {
this.pageNews.push(this.newsData.splice(0, 10));
this.headerNews.push(this.pageNews[i].splice(0, 1));
}
console.log(this.pageNews);
} catch (err) {
console.log(err);
}
},
immediate: true,
},
},
위 코드에서 중요한 부분은 fetch 함수와 await 키워드입니다. fetch 함수는 외부 API를 호출하고, await 키워드는 해당 함수가 완료될 때까지 기다립니다. 이를 통해 비동기 통신을 쉽게 구현할 수 있습니다
1-2 데이터 설정 및 API 호출
다음으로, data 속성에 필요한 데이터를 설정하고, computed 속성을 이용해 국가 코드를 동적으로 설정합니다. 또한, watch를 통해 countryCode가 변경될 때마다 API를 호출하여 데이터를 가져옵니다.
<script>
import NewsMain from "@/components/news/NewsMain.vue";
import Pagination from "@/components/layout/Pagination.vue";
export default {
name: "News",
data() {
return {
newsData: [],
totalItems: 1,
currentPage: 1,
itemPerPage: 10,
headerNews: [],
pageNews: [],
};
},
components: {
NewsMain,
Pagination,
},
computed: {
countryCode() {
// 로케일에 따라 국가 코드를 동적으로 설정
return this.$store.getters.fnGetLocale === "ko" ? "kr" : "us";
},
},
watch: {
countryCode: {
async handler(value, oldValue) {
// countryCode가 변경될 때마다 API 호출
try {
let response = await fetch(
`https://newsapi.org/v2/top-headlines?country=${value}&pageSize=100&apiKey=개인키`
);
let result = await response.json();
this.newsData = result.articles;
this.totalItems = result.totalResults;
this.pageNews = [];
this.headerNews = [];
console.log(value, oldValue);
for (
let i = 0;
i < Math.ceil(this.totalItems / this.itemPerPage);
i++
) {
this.pageNews.push(this.newsData.splice(0, 10));
this.headerNews.push(this.pageNews[i].splice(0, 1));
}
console.log(this.pageNews);
} catch (err) {
console.log(err);
}
},
immediate: true,
},
},
};
</script>
비동기 통신을 하는 이유
비동기 통신은 웹 애플리케이션에서 중요한 역할을 합니다. 특히 외부 API를 호출할 때 비동기 통신을 사용하면, 데이터를 가져오는 동안 사용자 인터페이스가 블록되지 않아 더욱 부드러운 사용자 경험을 제공합니다.
- 사용자 경험 향상: 데이터를 가져오는 동안 페이지가 멈추지 않아 사용자 경험이 향상됩니다.
- 효율적인 자원 사용: 서버로부터 필요한 데이터를 비동기적으로 가져오므로 자원을 효율적으로 사용할 수 있습니다
- 실시간 데이터 업데이트: 비동기 통신을 통해 실시간으로 데이터를 업데이트할 수 있습니다.
2. NewsMain 컴포넌트
2-1 HTML 구조 설정
NewsMain 컴포넌트에서는 headerNews와 pageNews를 이용해 뉴스를 표시합니다.
<template>
<div class="news__main">
<div class="row">
<div class="news__main__wrapper">
<h3 :class="{ dark: changeDarkMode }">{{ $t("[6].latestnews") }}</h3>
<div class="header__news">
<div class="header__news__right" :class="{ on: !windowWidth }">
<img
:src="getImg(headerNews[currentPage - 1][0]?.urlToImage)"
:alt="headerNews[currentPage - 1][0]?.source.name"
/>
</div>
<div class="header__news__left">
<h3>{{ headerNews[currentPage - 1][0]?.title }}</h3>
<p>{{ headerNews[currentPage - 1][0]?.description }}</p>
<a :href="headerNews[currentPage - 1][0]?.url" target="_blank"
>계속 읽기</a
>
</div>
<div class="header__news__right" :class="{ on: windowWidth }">
<img
:src="getImg(headerNews[currentPage - 1][0]?.urlToImage)"
:alt="headerNews[currentPage - 1][0]?.source.name"
/>
</div>
</div>
<div class="news__wrapper">
<div
class="news__card"
v-for="(item, idx) in pageNews[currentPage - 1]"
:key="idx"
>
<div class="card__img">
<img :src="getImg(item.urlToImage)" :alt="item.source.name" />
</div>
<h3>{{ item.title }}</h3>
<a :href="item.url" target="_blank">{{ $t("[6].readmore") }}</a>
</div>
</div>
</div>
</div>
</div>
</template>
2-2 데이터 설정 및 메서드 정의
props를 이용해 newsData, headerNews, pageNews, currentPage 데이터를 부모 컴포넌트로부터 받아옵니다.
<script>
export default {
name: "NewsMain",
props: ["newsData", "headerNews", "pageNews", "currentPage"],
data() {
return {
placeholder: "./assets/images/cardnews-1/TechTalks_evergreen_2x.jpg",
winWidth: 0,
};
},
created() {
this.winWidth = window.innerWidth;
},
computed: {
changeDarkMode() {
return this.$store.getters.fnGetDark;
},
windowWidth() {
return window.innerWidth > 390 ? true : false;
},
},
methods: {
getImg(src) {
return src ? src : this.placeholder; // 이미지가 없을 경우 기본 이미지를 반환
},
},
};
</script>
3. 컴포넌트 간 데이터 전달
props와 emit을 사용해 데이터를 부모 컴포넌트에서 자식 컴포넌트로 전달하고, 자식 컴포넌트에서 발생한 이벤트를 부모 컴포넌트로 전달합니다.
props를 이용한 데이터 전달:
- 부모 컴포넌트 (News.vue)에서 NewsMain 컴포넌트로 newsData, headerNews, pageNews, currentPage 데이터를 전달합니다.
- 자식 컴포넌트 (NewsMain.vue)에서는 props를 이용해 데이터를 받아와 화면에 표시합니다.
// 부모 컴포넌트 (News.vue)
<news-main
:newsData="newsData"
:headerNews="headerNews"
:pageNews="pageNews"
:currentPage="currentPage"
/>
// 자식 컴포넌트 (NewsMain.vue)
props: ["newsData", "headerNews", "pageNews", "currentPage"],
Vue.js를 이용해 외부 API를 호출하고, 비동기 통신을 통해 데이터를 가져와 화면에 표시했습니다! 이를 통해 실시간으로 데이터를 업데이트하고, 부드러운 사용자 인터페이스를 제공할 수 있습니다.