React HTTP 요청 개념 및 사용 방법
리액트 앱이나 일반적인 브라우저 앱에서 실행되는 자바스크립트 코드가 데이터베이스와 직접 통신하면 안된다.
클라이언트 내부에서 데이터베이스에 직접 연결을 하게 된다면 코드를 통해 데이터베이스의 인증 정보를 노출시키는 행위이기때문이다.
브라우저에서 실행되는 모든 자바스크립트 코드는 브라우저뿐만이 아니라 웹 사이트의 사용자들도 접근하고 읽을 수 있다.
따라서 리액트 앱 코드 내부에서 데이터베이스에 직접적으로 통신하는 것 대신에 다른 방법을 사용해야 한다.
예를 들어 백엔드 어플리케이션안데 데이터베이스 서버일 수도 있고 보통은 다른 서버일 경우가 많다.
그리고 데이터베이스와 통신하는 백엔드 어플리케이션은 사용자가 코드를 확인할 수 없기 때문에 데이터베이스의 인증 정보를 안전하게 저장할 수 있다.
백엔드 앱과는 API(Application Programming Interface)를 통해서 소통할 수 있으며 이 용어는 매우 넓은 개념이고 명확하게 정의된 인터페이스를 다루며 어떤 결과를 얻기 위한, 작업에 대한 규칙이 명확하게 정의되어있다.
HTTP 요청에 대한 API를 말할 때는 보통 REST, 또는 GraphQL API를 말한다.
주로 REST API를 사용하는데 특정 경로에 요청을 전송하게 되면 특정한 형식에 맞춰서 데이터를 전달해준다.
서로 다른 URL에 각각 다른 요청을 보내게 되면 그에 맞는 서로 다른 데이터들을 제공하는 방식이 REST API이다.
fetch 사용법
리액트는 자바스크립트 코드이기때문에 자바스크립트의 기능을 통해서 우리가 원하는 어떤 HTTP 요청이든 전달할 수 있다.
패키지 중에 axios라는 것이 있는데 어떤 자바스크립트 라이브러리를 사용하더라도 HTTP 요청 전송을 하고 이에 대한 반응을 매우 간단하게 할 수 있는 패키지이다.
또 자바스크립트 내에서 HTTP 요청을 전송하는 내장 메커니즘도 있는데 이를 Fetch API 한다.
이 Fetch API는 브라우저 내장형이며 데이터를 불러오고 이름과는 다르게 데이터 전송도 가능하다.
이에 대한 가장 단순한 형태는 우리가 요청을 전송하려는 URL을 문자열로 전달하기만 하면 된다.
그리고 이 함수에 두 번째 인자를 전달할 수 있는데 이 인자를 통해 다양한 선택사항을 지정할 수 있는 자바스크립트 객체를 전달할 수 있다.
예를 들어서 여기에 추가적인 header나 body 또는 HTTP 요청 method 등 이다.
fetch(`${REQUEST_URL}`, {
method: "POST",
headers: {
"Cotent-Type": "application/json",
},
body: JSON.stringify(user),
});
또한 호출에 대한 응답 역시 처리해야 하는데 fetch 함수는 프로미스객체를 반환하는데 이 객체는 우리가 잠재적으로 발생할 수 있는 오류나 호출에 대한 응답에 반응할 수 있게 해준다.
HTTP 요청 전송은 비동기 작업이기때문에 반환된 프로미스 객체는 어떤 즉각적인 행동 대신 어떤 데이터를 전달하는 객체이다.
밀리초, 또는 몇 초가 걸리는 작업이고 당연히 실패할 가능성도 있기때문에 코드 다음 줄로 작업을 계속하고 코드의 결과를 바로 사용할 수는 없다.
대신에 코드 실행의 결과는 미래의 어느 시점에서 확인할 수 있는데 then()을 추가하여 응답을 받을 때 호출되도록 한다.
response 객체는 요청 응답에 대한 데이터로 응답 헤더를 읽거나 상태 코드를 얻을 수도 있다.
API는 데이터를 JSON 형식으로 전송하고 내장 메소드가 json()을 통해서 코드에서 사용할 수 있는 자바스크립트 객체로 변환해준다.
fetch(`${REQUEST_URL}`)
.then((response) => {
return response.json();
})
.then((data) => {
const transformedUsers = data.results.map((userData) => {
return {
id: userData.id,
username: userData.username,
name: userData.name,
age: userData.age,
};
});
setUsers(transformedUsers);
});
프로미스를 다룰 때 이렇게 then chain 말고도 async와 await 문법을 사용할 수도 있다.
함수 앞에 async 예약어를 추가하고 프로미스를 반환하는 작업 앞에 await 예약어를 사용한다.
이 것은 단순히 코드 변환이며 백그라운드에서는 then 블록을 사용한 것과 같은 일을 한다.
겉보기엔 단계적으로 실행이 되는 동기화 작업으로 보이지만 백그라운드에서는 then 호출로 코드가 변환되기때문에 async, await 구문을 통해서 코드를 읽기 더 쉽게 한다.
const response = await fetch(`${REQUEST_URL}`);
const data = await response.json();
try-catch를 사용한 오류 처리와 로딩 처리도 가능하다.
fetch API는 에러 상태 코드를 실제 에러로 취급하지 않고 실제로 오류 상태 코드를 받아도 기술적인 오류로서 처리하지 않는다.
따라서 어떤 문제가 발생해도 이를 실제 오류로 처리하지 않는다는 것이다.
데이터를 가져오지 못했는데 어떤 작업을 하려고 할 때만 오류가 발생하게 된다.
Axios의 경우에는 요청 전송에 성공한다면 오류 상태 코드에 맞는 오류를 만들어서 전달한다.
fetch API를 사용한다면 직접 만들어야 한다.
try {
const response = await fetch(`${REQUEST_URL}`);
if (!response.ok) {
throw new Error("something went wrong!");
}
const data = await response.json();
setUsers(data);
} catch (error) {
setError(error.message);
}
useEffect, useCallback과 같은 hook과 함께 사용할 수 있다.
대부분의 어플리케이션에서는 특정 컴포넌트가 로딩되자마자 데이터를 가져오기도 한다.
HTTP 요청 전송은 일종의 사이드 이펙트로 컴포넌트의 상태를 바꿔버리기 때문에 useEffect를 사용한다.
const fetchUsersHandler = useCallback(async () => {
setIsLoading(true);
setError(null);
try {
const response = await fetch(`${REQUEST_URL}`);
if (!response.ok) {
throw new Error("something went wrong!");
}
const data = await response.json();
setUsers(data);
} catch (error) {
setError(error.message);
}
setIsLoading(false);
useEffect(() => {
fetchUsersHandler();
}, [fetchUsersHandler]);
'Frontend > React' 카테고리의 다른 글
React 사용자 입력 다루기 (0) | 2023.02.08 |
---|---|
React Custom Hooks 개념 및 사용 방법 (0) | 2023.02.07 |
React 오류 경계(Error Boundaries) 개념과 사용 방법 (0) | 2023.02.05 |
React 컴포넌트 생명주기 (0) | 2023.02.04 |
React 클래스형 컴포넌트 개념과 사용 방법 (0) | 2023.02.03 |
댓글