들어가며
최근 Fetch를 사용하던 중 단순히 javascript에서 사용할 때와
react에서 사용할 때 차이점이 있어 이를 공부하게 됐다.
fetch는 비동기로 동작하기 때문에 신경쓸 점이 많았다.
그리고 테스트 환경에서 사용하려면 추가적으로 필요한 설정이 있기에
이것까지 정리해보려 한다!
🍀 Fetch란?
ES6에 도입된 자바스크립트 내장 함수로, 클라이언트가 서버에 네트워크 요청을 보내서 정보를 받아올 때 사용함
- Promise 기반이라 비동기로 응답 받은 데이터를 다루기 쉬움
- 내장 함수라서 모듈 설치할 필요가 없음
기본 문법
fetch의 기본 메소드(생략시)는 get
임
fetch(url, {
method: "GET", // 기본값:GET (POST, PUT, DELETE, etc.)
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({...}),
});
💡 await
let response = await promise
- promise.then에 연결한 것처럼 비동기처리에 순서를 부여하고, 반환값을 받음
- async 함수 안에서만 동작함
Promise
일반 함수처럼 값을 받아오면 비동기적인 동작을 기다려주지 않기 때문에
비동기적인 함수의 값을 받는 방식이 따로 필요함
그 방식 중 하나가 Promise
💡 만약 프라미스 사용하지 않는다면?
데이터를 받고 콜백 함수를 중첩해서 불러오는 과정에서 에러 핸들링이 어렵다.
가독성이 나쁘고 콜백지옥이 생성되며 오류를 일으킬 확률↑
프라미스의 사용 효과
데이터를 받음 → (성공) 실행 → (실패) 에러 대응
프라미스는 성공/실패 각각의 경우에 js 내부 함수를 활용해서 실행되는 구조를 만들 수 있음
🍀 fetch로 통신하기
보통 fetch로 데이터를 받아오는 함수를 따로 만들고, 이를 컴포넌트에 불러온다.
그런데 프로미스를 받아와서 컴포넌트에서 처리할지
아니면 변환이 완료된 값 자체를 받아올지 형태는 다양하다.
javascript
데이터를 불러오는 함수를 분리해서 사용할 경우,
사용하는 함수를 async로 감싸 await로 값을 받으면 되므로 간단하다.
// utils/fetchData
export default async function fetchData() {
const url = 'http://localhost:3000/data';
const response = await fetch(url);
const { data } = await response.json();
return data; // 프로미스가 반환
}
// src/components/Table
async function Table() {
const data = await fetchData(); // 프로미스의 값을 받음
// 상태가 없기 때문에 데이터가 들어올 때 리렌더링되는 처리는 따로 필요함
}
react
데이터 전달 함수에서 프로미스를 반환 받느냐
아니면 변환 완료된 데이터를 받느냐로 나눠서 정리했다.
1. 데이터 전달 함수에서 프로미스를 반환받음
💡 주의사항
useEffect
의 콜백함수가 async 함수가 될 순 없음
그러므로 콜백함수 안에 async 함수를 만들고, 실행해야함
// hooks/useFetchData
export default async function useFetchData() {
const url = 'http://localhost:3000/data';
const response = await fetch(url);
const { data } = await response.json();
return data; // 프로미스가 반환됨
}
// components/Table
export default function Table() {
const [data, setData] = useState([])
useEffect(() => {
(async () => {
const fetchedData = await useFetchRestaurants();
setRestaurants(fetchedData)
})(); // 만들고 바로 실행
}, []);
return (
<div>
{data && (
<p>{data}</p>
)}
</div>
);
}
2. 데이터 전달 함수에서 변환 완료하여 전달받음
// hooks/useFetchData
export default function useFetchData() {
const [data, setData] = useState([]) // 여기서 상태값 설정
const fetchData = async () => {
const url = 'http://localhost:3000/data';
const response = await fetch(url);
const { data } = await response.json();
setData(data);
};
useEffectOnce(() => {
fetchData();
});
return data;
}
// src/components/Table
// 위에서 restaurants을 바로 넘겨주면 Table을 async 함수로 만들고 await으로 받아야 하는데
// 리액트의 함수 컴포넌트는 async 함수가 될수 없음
function Table() {
const restaurants = useFetchData();
}
💡 비동기로 전달받은 데이터 저장을 변수가 아닌 state에 하는 이유
비동기 작업은 동기적인 흐름과 별개로 작업이 처리됨
그래서일반 변수
에 할당할 경우, 비동기 작업이 완료(데이터가 받아와짐)되기 전에
해당 변수가 사용되는 동작이 실행되기 때문에 변수 안에 값은 할당되더라도 의도한대로 화면이 그려지지 않음
하지만상태값
을 사용하면 비동기 작업이 완료되어 상태값이 업데이트되면
컴포넌트가 리렌더링되기 때문에 무조건 데이터가 완료된 상태가 최종 출력값이 됨
🍀 에러처리
에러처리가 간단한 설명을 위해 위 코드에서 생략됐지만 비동기 통신시에 꼭 필요하다.
fetch는 404에러같은 HTTP 에러 응답을 받아도 promise를 reject하지 않고
네트워크 장애가 발생한 경우만 reject한다
이후 console.log(error)
로 error객체 확인 후, 처리하면 된다
error.ok
: URL 엔드포인트 성공적으로 요청됐는지 여부error.status
: 상태 코드 (성공하면 200)
async & await 사용 예시
리액트 2번 방법에 적용
//
// hooks/useFetchData
export default function useFetchData() {
const [data, setData] = useState([]) // 여기서 상태값 설정
const fetchData = async () => {
const url = 'http://localhost:3000/data';
const response = await fetch(url);
const { data } = await response.json();
if(!response.ok) {
console.log(err.message);
}
setData(data);
};
useEffectOnce(() => {
fetchData();
});
return data;
}
then & catch 사용 예시
fetch(url)
.then((response) => {
if (!response.ok) { // HTTP에러 발생 -> false
throw new Error( // catch로 에러 전달
`This is an HTTP error: The status is ${response.status}` // response.status = 404
);
}
return response.json();
})
.catch((err) => {
console.log(err.message);
});
🍀 테스팅 환경(Node.js)에서 fetch 사용하기
fetch는 자바스크립트 메서드이기 때문에 Node.js에서는 실행되지 않는다.
그렇기에 이를 도와주는 프레임워크가 필요하다.
GitHub에서 만든 fetch polyfill인 whatwg-fetch 설치해서 사용하면 된다
테스트 파일에 whatwg-fetch 불러오기
import 'whatwg-fetch';
테스트에서 사용시 모든 파일 상단에 쓰거나,
setupTests
파일 상단에 넣으면 됨
window.fetch()
로 사용하기fetch 작성시에 앞에 window를 붙여주면 끝!
window.fetch(url);
'Programming > Client' 카테고리의 다른 글
[Javascript] 파일 및 모듈 내보내기 (script / Common JS / ES Modules 그리고 Bundler) (1) | 2023.09.30 |
---|---|
[MSW] 브라우저, Node.js 환경에서 API 모킹하기 (0) | 2023.05.22 |
[Next.js] 웹 사이트 방문자 데이터 수집 (with GA: 구글 애널리틱스 ) (0) | 2023.05.08 |
메타버스는 어떻게 구현할까? (WebSocket, 서버 분할, 멀티 스레드) (0) | 2023.05.03 |
[Next.js] 플러그인 사용없이 SEO(검색 엔진 최적화)하기 (0) | 2023.04.24 |