리액트에서의 HTTP 요청
리액트에서 GET이나 POST 같은 HTTP 요청을 해서 데이터를 전송하거나, 어떤 데이터베이스에서 데이터를 받으려면 주의사항이 있다. 단순히 데이터베이스와 연결하면 되지라고 생각하면 심각한 보안문제를 겪을 수 있다.
브라우저에서 실행되는 모든 자바스크립트 코드는 브라우저뿐만 아니라 웹사이트의 사용자들도 접근하고 읽을 수 있기 때문에 리액트앱과 데이터베이스 간의 직접적인 연결은 해서는 안된다. 좀 더 자세히 말하면, SQL DB든 몽고DB같은 NoSQL이든 데이터베이스를 데이터베이스 서버에서 실행하는 것은 문제가 되지 않지만, 매우 불안정하거나 잘못 작성된 어플리케이션이 아니고서야 앱으로 직접 데이터를 가져오거나 저장하고 연결을 맺는 행위는 외부 환경에서는 절대 해서는 안되는 일 중의 하나라는 것이다. 만약 직접 연결을 하게된다면 이 연결코드를 통해 데이터베이스의 인증 정보를 노출시키게 된다.
그래서 직접 연결이 아닌 백엔드 어플리케이션을 사용해야 한다. 이는 브라우저 안에서 실행되지 않고 다른 서버에서 실행된다. 그 서버는 데이터베이스와 같은 서버일수도 있는데, 보통 다른 서버에서 실행된다. 백엔드 어플리케이션은 사용자가 이 백엔드 코드를 확인할 수 없기 때문에 데이터베이스의 인증 정보를 안전하게 저장할 수 있다. 따라서 리액트앱은 일반적으로 해당 백엔드 서버 또는 백엔드 API라 불리는 서로 다른 URL로의 요청을 전송하는 서버와 통신하게 된다.
오늘은 이 이론을 직접 구현하며 공부해보았다. 전체적인 파일은 강사로부터 받아서 HTTP 요청 부분만 같이 작성해보는 식으로 진행했다.
웹사이트에서 사용자가 스타워즈 영화정보를 알고싶어서 영화정보가 담긴 텍스트들이 있는 버튼을 누르면 별도의 서버에 있는 해당 정보들이 전송되서 사용자에게 보여지는 게 오늘의 구현목표였다.
우선, 외부의 데이터를 가져오는 것이기에 나타나는 정보들이 언제든 달라질 수 있기 때문에 최상위 컴포넌트에서 상태관리를 했다. 초기값은 빈 배열로 지정해주었다.
fetchMoviesHandler 함수는 데이터를 가져오는 함수인데, 함수가 실행되었을 때 스타워즈 API에서 데이터를 가져오기 위해 fetch 메서드를 사용하여 괄호 안에 이 API의 주소를 적어주었다. 이 fetch는 promise 객체를 반환하기 때문에, 이 promise 객체에서 사용되는 then 메서드를 사용해서 이 객체가 성공적으로 해결될 때 호출되는 함수를 만들어서 response를 json형식으로 반환하도록 했다.
💡 fetch 메서드: 웹 브라우저에서 제공하는 API로, 네트워크를 통해 리소스를 가져오는 비동기적인 작업을 수행하는 메서드이다. fetch를 사용하여 서버로 HTTP 요청을 보내고, 서버로부터 응답을 받을 수 있다.
fetch는 fetch(url, option)으로 구성되는데, url 인자는 요청을 보낼 URL이고, option은 선택사항이며, 요청 메서드나 헤더, 바디 등을 지정할 수 있는 추가 옵션이다. 기본값은 GET 요청으로 되어있다.
이 fetch는 프로미스 객체를 반환하는데, 응답처리를 위해 then() 메서드를 사용하여 성공 콜백함수와 오류 콜백함수를 등록할 수 있다. 응답은 Response 객체로 표현되며, 해당 객체를 사용해서 응답의 상태 코드, 헤더, 본문 등을 확인할 수 있다. 오류처리는 catch() 메서드를 사용할 수 있다.
그리고 then 메서드를 한번 더 사용해서 data 매개변수로 받은 외부데이터의 results 배열을 맵핑해서 새로운 키-값의 배열로 반환해주었다. 이후에 상태관리함수의 값을 맵핑한 새 배열이 있는 상수로 지정해주었다. 이렇게 then 메서드를 한번 더 사용하면 전달받은 데이터의 변환이 끝날 때 작동하게 된다.
그 아래 반환문에서는 영화정보를 가져오는 버튼에 클릭 이벤트리스너를 만들어서 fetchMoviesHandler 함수를 연결해주었다. 또, 화면에 표출될 영화리스트 컴포넌트에는 상태값 movies를 movies 속성값으로 지정해주었다.
위 이미지는 fetch movies 버튼을 눌렀을 때 아래에 나타나는 영화리스트가 표출된 모습이다. 영화리스트 내의 정보들은 모두 스타워즈 API에 저장되어 있는 정보들이다.
그런데 이렇게 불러와보니 사용자 입장에서 불편할 수 있는 점이 나타났다.
영화정보를 가져오는 도중에 버튼을 눌렀는데 아래에 아무런 문구도 표시되지 않아서 사이트가 멈춘 것으로 착각할 수 있어보였다. 나도 수업을 진행할 때는 새로고침을 몇번 눌렀었다.
그래서 오류처리를 넣기 전에 함수코드를 간결화작업을 해주었다. 기존의 코드도 비동기코드였지만, async와 await를 사용해서 더 간결한 비동기코드가 되었다. async와 await는 promise와 함께 사용되는데, 프로미스 체인을 사용하는 것보다 코드가 간결해지고 가독성이 좋아지는 장점이 있다. 그래서 위 코드에서는 then 메서드를 삭제했다.
💡 async 함수: async는 함수 선언 앞에 위치하여 해당 함수를 비동기 함수로 만든다. 이렇게 만들어진 비동기 함수 내에서는 await 키워드를 사용할 수 있다. 또, async 함수는 항상 promise를 반환한다. 이 프로미스는 비동기 작업이 완료되고 결과가 해결된 값을 가지게 된다.
💡 await 표현식: await는 async 함수 내에서만 사용이 가능하며, 프로미스가 처리되고 결과를 반환할 때까지 함수 실행을 일시 정지시킨다. 일반적으로 await는 프로미스를 반환하는 비동기 함수나 프로미스 객체 앞에 사용되며, await 표현식의 평가 결과는 프로미스가 처리되고 반환된 값이 된다.
isLoading 상태값은 오류처리를 위해 만든 값이다. 초기값은 false로 하고, fetchMoviesHandler 함수가 실행되면 값을 true로 변경하도록 했다. 그리고 setMovies 값으로 맵핑한 객체값이 나오면 다시 false로 해서 보이지 않도록 했다.
반환문도 오류처리를 반영해주었다. 영화리스트 자체를 로딩중이 아니고 영화데이터가 있을 때만 나타나도록 했고, 로딩중이 아닌데 데이터가 없다면 영화를 찾을 수 없다는 문구가 뜨도록 했다. 그리고 로딩중일 때는 로딩중이라는 문구가 나타나도록 했다.
결과는 위 이미지와 같다.

'React' 카테고리의 다른 글
리액트에서의 양식 및 사용자 입력작업 (0) | 2023.06.14 |
---|---|
HTTP 요청 심화, 커스텀 훅 (0) | 2023.06.02 |
useCallback, state 스케쥴링, 클래스형 컴포넌트 (0) | 2023.05.26 |
리액트의 작동원리, 자식 컴포넌트 재평가, react.memo() (0) | 2023.05.25 |
음식주문앱 만들면서 복습하기(3) (0) | 2023.05.24 |