JiSoo's Devlog
[Udemy React 완벽 가이드] HTTP 요청 보내기 본문
프론트엔드와 백엔드를 연결하기 위해서는 HTTP 요청을 사용해야 한다
그래야 리액트 앱 내에서 HTTP 요청을 백엔드로 보내 데이터를 요청하거나 바꾸도록 요청할 수 있다
데이터베이스와 소통해야 한다면 우리는 리액트로 클라이언트 쪽 코드를 쓰는 것
Endpoint라고 불리는 백엔드 API를 사용하면 되는데 이건 특정 요청만 받는 URL
API는 두 시스템이 상호작용할 수 있게 하는 프로토콜의 총집합
Endpoint는 API가 서버에서 리소스에 접근할 수 있도록 가능하게 하는 URL, 즉 요청을 받아 응답을 제공하는 서비스를 사용할 수 있는 지점을 의미한다
절대 데이터베이스와 내부 리액트 코드를 직접적으로 연결하려 하면 안 된다
그러면 데이터베이스 인증 정보가 노출된다
백엔드는 어떤 종류의 요청을 허락하고 어떤 요청들을 차단할지 통제한다
localStorage에서 데이터를 가져오기 위해 getItem 메소드를 사용하는 경우도 있다
로컬 저장소의 큰 장점은 실시간으로 접속할 수 있다는 것이고 가져오려는 데이터가 즉각 준비되어 있다는 것이다
내장 fetch함수는 리액트가 제공하는 게 아니라 브라우저가 직접 제공하는 것이다
HTTP 요청을 다른 서버들로 보내는 데 사용한다
기본적으로 fetch가 원하는 건 요청을 보내려는 서버의 URL
fetch는 Promise를 반환하는데 Promise는 표준 자바스크립트 객체로 해당 state에 따라 각 다른 값을 산출한다
그 값들에 접근하려면 fetch로 불러온 결과로 메소드들을 한데 묶을 수 있다
then 메소드를 추가할 수 있고 그 메소드에 함수를 전달해 함수를 정의하면 이 Promise가 해결되고 Response를 받고 나서 한 번 실행된다
최신 자바스크립트는 await 키워드를 사용해 이 Response들에 접근할 수 있다
하지만 이게 가능한 건 오직 이 함수에서 코드가 비동기(async)로 실행될 때인데 컴포넌트 함수들에게는 허용되지 않는다
fetch("http://localhost:3000/places").then((response)=>{
return response.json()
})
json 메소드는 JSON 형식의 데이터를 추출하는데 사용할 수 있다
JSON은 간단하게 텍스트 기반 데이터 형식이며 자바스크립트 배열과 객체와 비슷하다고 볼 수 있다
JSON 메소드는 또 다른 프로미스를 반환하기 때문에 또 다른 then 메소드를 추가할 수 있다
fetch("http://localhost:3000/places")
.then((response) => {
return response.json();
})
.then((resData) => {
setAvailablePlaces(resData.places);
});
하지만 이렇게 하면 무한 루프를 생성하게 되는 문제가 생긴다
useEffect로 해결하기
Effect 함수는 의존성이 바뀌었다는 전제 하에 항상 컴포넌트 함수가 실행된 직후 즉시 실행된다
useEffect(() => {
fetch("http://localhost:3000/places")
.then((response) => {
return response.json();
})
.then((resData) => {
setAvailablePlaces(resData.places);
});
}, []);
async await를 사용하기 위해 Effect 함수에서 새로운 함수 생성
useEffect(() => {
async function fetchPlaces() {
const response = await fetch("http://localhost:3000/places");
const resData = await response.json();
setAvailablePlaces(resData.places);
}
fetchPlaces();
}, []);
비동기로 정의하고 즉시 불러내기
HTTP 요청을 보낼 때 대부분 state와 도착할 데이터만 관리하지 않고 loading state도 함께 관리해야 한다
const [isFetching, setIsFetching] = useState(false);
useEffect(() => {
async function fetchPlaces() {
setIsFetching(true);
const response = await fetch("http://localhost:3000/places");
const resData = await response.json();
setAvailablePlaces(resData.places);
setIsFetching(false);
}
fetchPlaces();
}, []);
HTTP 요청을 보낼 때 에러 발생
데이터 fetching에 실패할 수 있다는 걸 항상 염두에 둬야 한다
실패하는 큰 이유 두 가지
1. 요청을 보내는 것에 실패하는 것
2. 요청을 보낼 때 백엔드에서는 성공적으로 전달되었지만 거기서부터 문제가 발생해 에러 응답을 보내는 경우
fetch 함수를 사용해 HTTP 요청을 보낼 때 응답이 에러 응답인지 확인할 수 있다
response.ok 속성을 확인하면 되는데 true면 200-300 정도의 상태 코드는 받고
false라면 400이나 500 정도의 상태 코드를 받는다
데이터를 가져올 때 흔하게 3가지 상태들이 함께 동작한다
const [availablePlaces, setAvailablePlaces] = useState([]);
const [isFetching, setIsFetching] = useState(false);
const [error, setError] = useState();
useEffect(() => {
async function fetchPlaces() {
setIsFetching(true);
try {
const response = await fetch("http://localhost:3000/places");
const resData = await response.json();
if (!response.ok) {
throw new Error("Failed to fetch places");
}
setAvailablePlaces(resData.places);
} catch (error) {
setError({
message:
error.message || "Could not fetch places, please try again later",
});
}
setIsFetching(false);
}
fetchPlaces();
}, []);
POST 요청으로 데이터 전송하기
fetch로 요청을 보낼 때 두 번째 인수에 나가는 요청들을 설정하는 설정함수가 와야 한다
const response = await fetch("http://localhost:3000/user-places", {
method: "PUT",
body: JSON.stringify({ places }),
headers: {
"Content-Type": "application/json",
},
});
메소드 속성을 설정하고, body 속성을 추가해 어떤 데이터가 요청 body에 첨부되어야 하는지 정의한다
나가는 요청 body에 대한 내용이 꼭 첨부될 수 있는 형식이어야 하는데 자바의 배열은 첨부할 수 있는 형식이 아니라서 JSON 형식으로 변환되어야 한다
요청에 첨부될 추가 메타데이터인 헤더도 추가해야 한다
'Frontend > React' 카테고리의 다른 글
[Udemy React 완벽 가이드] 컨텍스트 API & useReducer (0) | 2024.06.10 |
---|---|
[Udemy React 완벽 가이드] 리액트 쿼리/Tanstack 쿼리 (0) | 2024.06.01 |
[모던 리액트 Deep Dive] 8장 (0) | 2024.05.30 |
[모던 리액트 Deep Dive] 7장 (0) | 2024.05.23 |
[모던 리액트 Deep Dive] 6장 (0) | 2024.05.19 |