티스토리 뷰

Web/Vue.js

[Vue.js] 2. 데이터 받기(get)

HAN_PY 2020. 11. 17. 20:11
반응형

0. 들어가면서

우리는 앞에서 Vue를 설치하고 실행하는 방법과 Vue에 사용되는 문법에 대해 알아보았다. 궁금하면 아래의 주소를 따라가면 된다. 이제 배운 내용을 바탕으로 적용을 해보자.

han-py.tistory.com/66

 

[Vue.js] 1. 시작하기

0. 들어가면서 Vue를 처음 배우는 사람이라면 바로 이곳에서 시작해 보길 바란다. 전반적인 개념과 시작하는 방법이 적혀있다. 자바스크립트를 모르더라도 어느정도 구현할 수 있도록 노력했다.

han-py.tistory.com

 

 

 

Vue는 frontend다. 따라서 frontend인 뷰를 사용하기위해, 서버를 만들어서 데이터를 보내고 하기에는 시간이 너무 많이 든다. 그래서 일단 더미 데이터를 get방식으로 받아서 실습을 해볼까 한다.

 

 

더미 데이터(=가짜 데이터)를 JSON으로 제공하는 사이트로는 한국어를 제공해주는 Korean Json과 jsonplacdbolder가 있다. 각각을 구글 검색하면 쉽게 들어갈 수 있다. 우리는 영어로 되어있지만 데이터가 많은 Jsonplaceholder를 사용할 것이다. 아래의 사이트를 들어가서 스크롤을 내려보자.

 

jsonplaceholder.typicode.com/

 

JSONPlaceholder - Fake online REST API for testing and prototyping

When to use JSONPlaceholder is a free online REST API that you can use whenever you need some fake data. It can be in a README on GitHub, for a demo on CodeSandbox, in code examples on Stack Overflow, ...or simply to test things locally. Resources JSONPlac

jsonplaceholder.typicode.com

스크롤을 내리다 보면 아래의 내용이 나온다. 눌러보면 관련 json을 확인할 수 있다. 여기서는 photos를 사용하 볼까 한다.

 

photos를 눌렀을 때의 주소는 아래와 같다.

https://jsonplaceholder.typicode.com/photos

 

0.1. 시작전 Vue 기본 코드 보기

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">

    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {},
            methods: {},
        })
    </script>

</body>
</html>

methods란 객체 안에 정의되어 있는 함수로 무조건 function으로 되어있다. 그리고 완성 코드를 먼저 보고 코드를 하나씩 뜯어보자.

 

1. 데이터 받기

 우선은 GET 요청으로 위의 url 주소를 누르면 데이터를 받아오는 로직을 작성해 보자.

5000개 data 받기

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Scroller</title>
</head>
<body>
    <div id="app">
        <button @click='getPhotos'>GET PHOTOS</button>
        <div v-for="photo in photos">
            <h5>{{ photo.title }}</h5>
            <img :src="photo.thumbnailUrl" :alt="photo.title">
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <script>
        const app = new Vue({
            el: '#app',
            data: {
                photos: [],
            },
            methods: {
                getPhotos: function () {  //getPhots함수는 메서드정의. 할때는 반드시 function 키워드쓴다
                    axios.get('https://jsonplaceholder.typicode.com/photos?_page=1&_limit=5')
                        .then((res) => { 
                            this.photos = res.data 
                        }) //인자로 넣어주는 함수니 콜백함수. 함수가 메서드가 아니므로 this는 method다. 콜백함수는 무조건 화살표쓴다
                        //.then(res => this.photos = res.data ) //리턴 없고 인자도 하나니 이렇게 가능하다
                        .catch(err => console.error(err))    
                
                
                }
            },
        })
        
    </script>

</body>
</html>

1.1 코드 해석

무슨 말인지 모를 수 있다. 하나씩 이해를 해보자.

  • 우선은 data에 데이터를 넣기 위한 photos 리스트를 초기화 해 넣어준다.
  • 그리고 methods에 버튼 관련 함수를 getPhotos를 넣어준다.
  • ajex요청을 위해 우리는 axios를 사용한다. 아래의 깃헙에 들어가서 CDN을 추가해주자

github.com/axios/axios

 

axios/axios

Promise based HTTP client for the browser and node.js - axios/axios

github.com

axios CDN은 아래와 같다.

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

 

1.2 콜백 함수와 this

 위의 코드에서 methods 부분만 먼저 보자.

            methods: {
                getPhotos: function () {  //getPhots함수는 메서드정의. 할때는 반드시 function 키워드쓴다
                    axios.get('https://jsonplaceholder.typicode.com/photos?_page=1&_limit=5')
                        .then((res) => { 
                            this.photos = res.data 
                        }) //인자로 넣어주는 함수니 콜백함수. 함수가 메서드가 아니므로 this는 method다. 콜백함수는 무조건 화살표쓴다
                        //.then(res => this.photos = res.data ) //리턴 없고 인자도 하나니 이렇게 가능하다
                        .catch(err => console.error(err))    
                
                
                }
            },
  • axios.get에는 넣을 url을 넣어준다.
  • 콜백 함수란 함수의 인자 안에 들어간 함수이다. 즉,. than이 실행할 때 인자가 들어간 () 안에 넣어준 함수가 콜백 함수라고 할 수 있다. .than에는 콜백 함수가 있는 것을 확인할 수 있다.

axios 안에 있는 then을 뜯어보자. `this가 무엇을 가리킬까?`

.then(function (res) { console.log(this.photos) })

 위의 코드는 function 키워드를 콜백 함수에 쓴 것이다. 콘솔을 열어서 확인해보자

> app.getPhotos()

< undefined

라고 나온다. 그러면 then을 아래처럼 바꿔서 this도 확인해보자.

 

.then(function (res) { console.log(this) })

> app.getPhotes()

< window

윈도우(최상위 폴더)가 뜬다. 윈도우가 뜨는 이유는 위에서 정의한 함수는 method가 아니기 때문이다. method가 아니기 때문에 app을 가리키지 않고 윈도우를 가리킨다. 그러면 어떻게 this가 app을 향하게 만들 수 있을까?

화살표 함수를 쓰면 된다. 결론부터 말하자면, 콜백 함수를 사용할 때는 반드시 화살표 함수를 쓰자.

 

.then(function (res) => { console.log(this) })

> app.getPhotos

< Vue

이제야 this가 우리가 했던 Vue인스턴스를 가리킨다. 아래의 사진을 보면 data도 잘 불러와서 사용되는 것을 볼 수 있다.

 

 

정리.

- method(getPhotos) 정의할 때는 function을 쓴다.

- 콜백함수를 쓸 때는 화살표함수를 쓰자.

 

 

최종은 아래와 같다.(화살표 함수에서는 아래와 같이 function을 지우고 쓸 수 있다.)

.then((res) => { this.photos = res.data })

아래와 같이 인자가 하나인 경우는 더 짧게 쓰는 것도 가능하다. 리턴 문도 한 줄인 경우는 중괄호도 생략 가능하다.

.then(res => this.photos = res.data )

따라서, 위의 두 개는 같은 코드이다.

 

 

 

1.3 console.log()와 console.error() 차이

두 개의 차이는 콘솔 창에 뜨는 색이 console.log는 검정이 뜨고, console.error는 빨강이 뜬다.

 

 

 

1.4 생각해보기

axios.get('jsonplaceholder.typicode.com/photos)

위의 코드는 5000개를 한 번에 보여주는 코드다. 실행해보면.... 한새월이다. 그렇기 때문에 이제 페이지를 나눠보자.아래의 홈페이지를 들어가서 README부분을 보면 Paginate가 있다. Paginate쪽을 읽어보니 5000개를 한번에 보여주지 말고 나눠서 보여줄 수 있을 것 같다.

https://github.com/typicode/json-server

 

typicode/json-server

Get a full fake REST API with zero coding in less than 30 seconds (seriously) - typicode/json-server

github.com

보니 page만 적으면 디폴트 10개만 주고 뒤에 limit를 적어주면 그 적은 개수만큼 주는 것 같다. 적용해보자.

 

 

 

2. 데이터를 분할해서 연속받기

누를 때마다 데이터를 5개씩 추가해서 보이게 만들어 보자!

따옴표를 백 틱으로 바꾼다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Scroller</title>
</head>
<body>
    <div id="app">
        <button @click='getPhotos'>GET PHOTOS</button>
        <div v-for="photo in photos">
            <h5>{{ photo.title }}</h5>
            <img :src="photo.thumbnailUrl" :alt="photo.title">
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <script>
        const app = new Vue({
            el: '#app',
            data: {
                photos: [],
                page: 1,
            },
            methods: {
                getPhotos: function () {  //getPhots함수는 메서드정의. 할때는 반드시 function 키워드쓴다
                    axios.get(`https://jsonplaceholder.typicode.com/photos?_page=${this.page}&_limit=5`)
                        .then((res) => { 
                            this.photos = res.data 
                        }) //인자로 넣어주는 함수니 콜백함수. 함수가 메서드가 아니므로 this는 method다. 콜백함수는 무조건 화살표쓴다
                        //.then(res => this.photos = res.data ) //리턴 없고 인자도 하나니 이렇게 가능하다
                        .catch(err => console.error(err))    
                
                
                }
            },
        })
        
    </script>

</body>
</html>

 

페이지를 data에 넣어주자. 그러면 ${this.page}에 1이 담긴다. 즉, 첫 페이지를 볼 수 있다.

 

url처럼 긴 문장을 잘라서 params로 설정해 보자.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Scroller</title>
</head>
<body>
    <div id="app">
        <button @click='getPhotos'>GET PHOTOS</button>
        <div v-for="photo in photos">
            <h5>{{ photo.title }}</h5>
            <img :src="photo.thumbnailUrl" :alt="photo.title">
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <script>
        const app = new Vue({
            el: '#app',
            data: {
                photos: [],
                page: 1,
            },
            methods: {
                getPhotos: function () {  //getPhots함수는 메서드정의. 할때는 반드시 function 키워드쓴다
                    const options = {
                        params:{
                            _page: this.page,
                            _limit: 5,
                        }
                    }
                    axios.get('https://jsonplaceholder.typicode.com/photos', options)
                        .then((res) => { 
                            this.photos = res.data 
                        }) //인자로 넣어주는 함수니 콜백함수. 함수가 메서드가 아니므로 this는 method다. 콜백함수는 무조건 화살표쓴다
                        //.then(res => this.photos = res.data ) //리턴 없고 인자도 하나니 이렇게 가능하다
                        .catch(err => console.error(err))    
                
                
                }
            },
        })
        
    </script>

</body>
</html>

 

 

 

이제 페이지 넘기기. 요청할 때마다 페이지를 1씩 올려 보자.

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Scroller</title>
</head>
<body>
    <div id="app">
        <button @click='getPhotos'>GET PHOTOS</button>
        <div v-for="photo in photos">
            <h5>{{ photo.title }}</h5>
            <img :src="photo.thumbnailUrl" :alt="photo.title">
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <script>
        const app = new Vue({
            el: '#app',
            data: {
                photos: [],
                page: 1,
            },
            methods: {
                getPhotos: function () {  //getPhots함수는 메서드정의. 할때는 반드시 function 키워드쓴다
                    const options = {
                        params:{
                            _page: this.page++,
                            _limit: 5,
                        }
                    }
                    
                    axios.get('https://jsonplaceholder.typicode.com/photos', options)
                        .then((res) => { 
                            this.photos = res.data 
                        }) //인자로 넣어주는 함수니 콜백함수. 함수가 메서드가 아니므로 this는 method다. 콜백함수는 무조건 화살표쓴다
                        //.then(res => this.photos = res.data ) //리턴 없고 인자도 하나니 이렇게 가능하다
                        .catch(err => console.error(err))    
                
                
                }
            },
        })
        
    </script>

</body>
</html>

 

주의) ++

> let a = 1

> console.log(a++)

< 1

> a

< 2

즉, a를 기존 값으로 사용한 후에 +1을 해주게 된다.

만약 ++a이면 올린 후에 쓰는 것이다. 2부터 나온다.

 

 

 

위의 코드는 data가 아래에 추가되는 게 아니라 페이지가 넘어가서 동작을 한다. 다르게 코드를 짜야겠다.

파이썬처럼this.photos += res.data 는 불가하다.

왜냐하면 JS에서는

>[1, 2, 3] + [4, 5, 6]

<"1,2,34,5,6"  

이 되기 때문이다.

 

push 쓰면 2차원 배열이 된다;;

const arr = [1, 2, 3]

arr.push([4, 5, 6])

<[1, 2, 3, [4, 5, 6]]

 

concat 쓴다.(고전)

const arr = [1, 2, 3]

const arr2 = [4, 5, 6]

arr.concat(arr2)

<[1, 2, 3, 4, 5, 6]

 

이렇게 우리 쓴다

const arr = [1, 2, 3]

const arr2 = [4, 5, 6]

const arr3 = [...arr...arr2]            <= ...은 그냥 쓴 게 아니고, 안에 있는 배열을 빼주는 것이다.

> arr3

<[1, 2, 3, 4, 5, 6]

 

 

정리

concat은 잘 안 쓴다.

this.photos += res.data 말고 아래처럼 쓴다.

this.photos = [...this.photos, ...res.data]

 

주의사항)... 같은 경우에 옛날 브라우저는 안 돌아갈 수 있어서 concat이 안전하긴 하다.

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Scroller</title>
</head>
<body>
    <div id="app">
        <button @click='getPhotos'>GET PHOTOS</button>
        <div v-for="photo in photos">
            <h5>{{ photo.title }}</h5>
            <img :src="photo.thumbnailUrl" :alt="photo.title">
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <script>
        const app = new Vue({
            el: '#app',
            data: {
                photos: [],
                page: 1,
            },
            methods: {
                getPhotos: function () {  
                    const options = {
                        params:{
                            _page: this.page++, // 기존값 가져와서 쓰고나서 1을 올린다//++page는 올리고 쓴다
                            _limit: 5,
                        }
                    }
                    this.page++ // 기존값 가져와서 쓰고나서 1을 올린다
                    axios.get('https://jsonplaceholder.typicode.com/photos', options)
                        .then((res) => { 
                            this.photos = [...this.photos, ...res.data] 
                        }) 
                        .catch(err => console.error(err))    
                
                
                }
            },
        })
        
    </script>

</body>
</html>

 

 

버튼 꾸미기

이제 style을 이용하여 버튼을 아래에 fix (절대 위치) 시킨다.

이때 button은 id 말고 class로 한다.(id는 JS에게 양보하자.)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        .button-bottom {
            position: fixed;
            right: 100px;
            bottom: 100px;
        }
    </style>
    <title>Scroller</title>
</head>
<body>
    <div id="app">
        <div id-for="photo in photos">
            <h5>{{ photo.title }}</h5>
            <img :src="photo.thumbnailUrl" :alt="photo.title">
        </div>
        <button @click='getPhotos' class="button-bottom">GET PHOTOS</button>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <script>
        const app = new Vue({
            el: '#app',
            data: {
                photos: [],
                page: 1,
            },
            methods: {
                getPhotos: function () {  
                    const options = {
                        params:{
                            _page: this.page++, // 기존값 가져와서 쓰고나서 1을 올린다//++page는 올리고 쓴다
                            _limit: 5,
                        }
                    }
                    this.page++ // 기존값 가져와서 쓰고나서 1을 올린다
                    axios.get('https://jsonplaceholder.typicode.com/photos', options)
                        .then((res) => { 
                            this.photos = [...this.photos, ...res.data] 
                        }) 
                        .catch(err => console.error(err))    
                
                
                }
            },
        })
        
    </script>

</body>
</html>

 

 

 

위에 fix는 절댓값으로 버튼을 고정이 쓰기 때문에 화면 크기가 변화함에 따라서 변화가 없어서 너무 딱딱하다

따라서 뷰포트(눈으로 볼 수 있는 브라우저 크기)를 적용하자.

vw- 가로 (viewport width)

vh- 세로 (viewport height)

동적으로 화면 바꿨을 때 자동으로 맞춰준다. 10vw, 10vh로 하면 우측 아래의 위치에 10분의 1 지점에 버튼이 생긴다고 보면 된다.

 

        .button-bottom {

            positionfixed;

            right10vw;           - 전체 길이의 10분의 1인 위치이다

            bottom: 20vh;        - 전체 길이의 5분의 1인 위치이다

        }

이렇게 바꿔준다.

 

 

3. 마무리

이제 우리는 lifecycle hook에 대해 알아보러 가자. 간단히 말하면, 페이지가 로드될 때 특정 함수를 실행시키는 방법이라고 생각하면 된다. 아래의 링크를 타고 가자

han-py.tistory.com/280

 

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함