<script>
...
// button 클릭해서 request 날리는 로직
fetch(URL,{
method:"GET | POST | DELETE | PATCH | ...",
header:{
'~':'~'
},
body:JSON.stringfy({
key:value(this.~~)
})
})
...
</script>
fetch 메서드의 첫번재 인수는 URL이고 2번째 인수로 request을 구성하는 JavaScript 객체이다.
이 객체 안에 method 프로퍼티를 써 넣는다.
기본으로 값은 GET 문자열이지만 POST로도 설정할 수 있다.
그리고 발신 요청에 headers 즉 메타데이터도 추가해야 하는데 정확히 말하면 Content-Type 헤더를 application/json으로 설정해서 JSON 형식의 일부 데이터가 요청에 추가된 걸 서버에 알려야 한다.
기본적으로 텍스트이지만 특정 방식으로 쓴 텍스트 형식으로 기기가 파싱하고 읽기 아주 쉽다.
body에 데이터를 실어서 보낼 때 JSON.stringfy로 보내면 JS 객체를 JSON 형식(문자열)으로 바꿔주는 메서드이다.
<script>
...
// button 클릭해서 request 날리는 로직
fetch(URL,{
method:"GET | POST | DELETE | PATCH | ...",
}).then(function(res){
if(res.ok){
return res.json();
}
});
...
</script>
Get method는 기본값이라 따로 써줄 필요가 없다.
자 그럼 어떻게 결과값에 접근할 수 있을까 여기서 바로 Promise 개념이 도입된다.
JavaScript는 이전 코드의 결괏값이 도착할 때까지 코드 실행을 멈추고 기다리는 언어가 아니다.
fetch는 데이터가 도착하면 이를 수신할 수 있는 객체를 반환하고 그 후 데이터가 도착했을 때 코드를 설정 및 실행한다.
이때 리스너는 fetch의 결괏값 뒤에 then 메서드를 추가하여 설정하는데 then 메서드에는 함수가 들어간다.
이 함수는 결괏값이 나왔을 때 실행되는데 데이터가 도착하면 브라우저에서 자동으로 실행하는 함수이다.
이 응답을 파싱할 수 있는데 if 문을 통해서 응답, 즉 response가 ok인 경우 자동으로 브라우저가 찾은 response 객체가 성공적인 요청인지 아닌지를 ok 프로퍼티로 가려낸다.
서버가 404 코드를 반환하는 경우라면 ok가 아니고 반면 ok 상태라면 해당 응답을 통해서 데이터를 읽어들일 수 있다.
또 res.json()
메서드로 응답 데이터를 파싱할 수 있다.
그리고 해당 응답 데이터를 반환할 수 있다. 이는 then 블록을 통해 생성된 프로미스를 반환할 수도 있고 첫 번째 then 메서드 다음에 또 다른 then 메서드를 추가할 수도 있다. 이 then 메서드는 return 프로미스가 완료되었을 때 트리거된다.
...
// button 클릭해서 request 날리는 로직
fetch(URL,{
method:"GET | POST | DELETE | PATCH | ...",
}).then((res)=>{
if(res.ok){
return res.json();
}
}).then((data)=>{
const results = []
for(const id in data){
results.puch({id:id, name:data[id].name, rating:data[id].rating});
}
this.데이터프롭 = results;
});
...
</script>
위 then(function(data){})
에는 response.json을 통해 반환된 실제 data를 입력한다.
이때 data는 JS 객체이기 때문에 변환을 해주어야한다.
그리고 TypeError : Cannot set property 'results' of undefined at eval
error는 this. 키워드가 context 오류가 나서 생기는 문제인데 이때는 =>
를 사용하여 해당 함수 내부에 있는 this 키워드가 외부에 있는 this 키워드와 동일한 컨텍스트를 참조하도록 하면 된다.
fetch('https://vue-http-demo-85e9e.firebaseio.com/surveys.json', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: this.enteredName,
rating: this.chosenRating,
}),
});
import axios from 'axios';
...
axios.post('https://vue-http-demo-85e9e.firebaseio.com/surveys.json', {
name: this.enteredName,
rating: this.chosenRating,
});
장점 : 자동으로 Content-Type헤더를 설정하고 본문 데이터를 JSON으로 자동 변환한다.
단점 : 출하하는 웹 앱의 크기가 증가한다
fetch()는 프로미스를 반환하므로 then(), catch() 및 async/ await 을 사용할 수 있다.
Axios의 경우 Promise도 반환한다는 점에서 동일하다.
이제는 페이지가 로드될 때 자동으로 데이터를 꺼내와서 보여주는 코드를 작성해보자.
이는 우리가 배웠던 생명주기를 이용하면 된다!!
우선 mounted 훅을 사용해보자. mounted 훅은 Vue 앱이 마운트되었을 때 트리거된다.
그래서 기존에 methods
에 http req 메서드를 this.로 참조하여 실행하게끔 하면 된다.
우선 로딩 state를 하나 만들어서 data(){}
속성에 추가해준다.
그리고 methods에 http method에 각 fetch API마다 loading state를 true로 만들어준다.
이때 주의할 점이 있는데 fetch가 모두 끝난 지점에 추가하면 fetch 메서드가 끝나기도 전에 바로 실행이 되기 때문에 fetch 메서드 내부에 작성해야한다.
그리고 <template>에 v-if, v-else 속성을 사용하여 로딩 상태를 구현해주면 된다.
...
// button 클릭해서 request 날리는 로직
methods:{
httpReqMethod(){
this.isLoading = true
this.error = null
fetch(URL,{
method:"GET | POST | DELETE | PATCH | ...",
}).then((res)=>{
if(res.ok){
return res.json();
}
}).then((data)=>{
const results = []
for(const id in data){
results.puch({id:id, name:data[id].name, rating:data[id].rating});
}
// data(){} 에 http res data 넣는 부분
this.데이터프롭 = results;
}).catch((error)=>{
this.에러프롭 = '예를들어 데이터를 가져오는데 실패함. 다시 ㄱㄱ';
});
}
}
.catch()
는 앞서 작성한 .then
블럭이나 fetch()
API에서 발생한 오류들을 포착하여 처리한다.
그리고 개발자는 console.log에 찍힌 error를 사용자에게 알려줄 필요가 있다.
그리고 이것을 구현하기위해 data(){}
state를 하나 더 만들어 관리해줄 필요가 있다. 예를들어 error:null
물론 해당 에러를 구체적으로 에러메시지를 표시해줄 수도 있다.
또한 새로운 요청을 전송할 때마다 error가 리셋되어있어야한다. 따라서 methods에 http req 메서드에 error를 항상 초기화해주는 구문이 있어야한다.
또한 해당 로직을 loading => error => 데이터 없음 => 데이터 표시 순으로 <tamplate> 로직을 짜주면 좋다.
...
// button 클릭해서 request 날리는 로직
methods:{
httpReqMethod(){
this.isLoading = true
this.error = null
fetch(URL,{
method:"GET | POST | DELETE | PATCH | ...",
}).then((res)=>{
if(res.ok){
return res.json();
}
}).then((data)=>{
const results = []
for(const id in data){
results.puch({id:id, name:data[id].name, rating:data[id].rating});
}
// data(){} 에 http res data 넣는 부분
this.데이터프롭 = results;
}).then(res=>{
if(res.ok){
//...
} else {
throw new Error('에러 구문');
}
}).catch((error)=>{
this.에러프롭 = '예를들어 데이터를 가져오는데 실패함. 다시 ㄱㄱ';
});
}
}