23.07.05
Axios : node.js와 브라우저를 위한 Promise 기반 http 클라이언트 => http를 이용해서 서버와 통신하기 위해 사용하는 패키지 …?
즉, 간단하게 말하면 클라이언트는 서버와 통신해야하는데 이때 서버와 통신하기 위해 사용하는 패키지가 Axios로, Axios는 http 클라이언트임 !
yarn add axios 패키지 설치 필요
json-server 설치 필요
+) 기본적으로 리액트와 db.json은 다른 포트를 사용하고 있으므로 완전히 다른 공간에 있다고 생각해야 함 !
json 서버 공식 문서
참고 링크

서버 통신을 한다는 것 = ‘비동기’
비동기 통신 = 제어권이 나한테 없음 => 즉, 서버의 상태를 우리는 기다려야 함
// db.json
{
"todos": [
{
// 이때 id를 "1"이라고 문자형으로 적어줘서 id가 숫자 순서대로 나오는게 아니라 랜덤 id로 출력되었음 ...
"id": 1,
"title": "react"
},
{
"id": 2,
"title": "node"
},
{
"id": 3,
"title": "spring"
}
]
}
const fetchTodos = async () => {
const { data } = await axios.get("http://localhost:4001/todos");
// await을 써주지 않으면 response는 Promise의 <pending>으로 찍힘
// => 응답을 받기 전 콘솔창이 먼저 찍히기 때문에 ...
console.log("data", data);
setTodos(data);
};
// submit을 눌렀을 때 POST하므로 onSubmitHandler 또한 async 함수, async 함수는 항상 인자가 필요
const onSubmitHandler = async () => {
axios.post("http://localhost:4001/todos", inputValue);
// post를 하고나서 setTodos를 통해 state를 추가해주고 나면 DB에는 쌓이지만,
// state에서는 자동으로 id값이 갱신되지 않기 때문에 새로고침 하고나서야 갱신됨
// setTodos([...todos, inputValue]);
// 그래서 차라리 다시 fetchTodos를 통해 데이터를 다시 조회하는게 나음
fetchTodos();
};
const onDeleteButtonClickHandler = async (id) => {
axios.delete(`http://localhost:4001/todos/${id}`);
setTodos(
todos.filter((item) => {
return item.id !== item;
})
);
};
// targetId를 통해 삭제할 데이터를 찾고 그 id 안에 title을 새로 입력한 contents로 바꿔주는 것
const onUpdateButtonClickHandler = async () => {
axios.patch(`http://localhost:4001/todos/${targetId}`, {
title: contents,
});
fetch는 axios와 비슷함
그런데 fetch는 자바스크립트 내장 라이브러리로 따로 npm이나 yarn을 통해 패키지 설치할 필요가 없음
그렇지만 fetch는 미지원 브라우저 존재, 개발자에게 불친절한 response, axios에 비해 부족한 기능 등 이러한 단점들이 있어ax서 ios 사용할 예정
크게 아래 2가지 case에서 차이를 보자면
fetch(url)
.then((response) => response.json())
.then(console.log);
fetch를 사용해 데이터를 읽어오면 fetch().then()을 한 상태여도 JSOP 포맷의 응답이 아니기 때문에 response.json()을 한번 더 해줘야 해서 fetch로 데이터를 요청하는 경우 두 개의 .then()이 필요
const url = "https://jsonplaceholder.typicode.com/todos";
axios.get(url).then((response) => console.log(response.data));
반면, axios를 사용해 데이터를 읽어오면 response가 기본적으로 JSOPN 포맷이어서, response.data로만 사용하면 됨
const url = "https://jsonplaceholder.typicode.com/todos";
axios
.get(url)
.then((response) => console.log(response.data))
.catch((err) => {
if (err.response) {
// 여기서 error handling 가능 !!!!!!!!!!!!!!
}
});
axios.get()요청이 반환하는 Promise 객체(= 응답, response)가 갖고있는 상태코드가 2xx의 범위를 넘어가면 거부함
=> 따라서, 바로 catch() 부분을 통해 error handling이 가능
=> 즉, 각 상태코드에 맞게 무슨 문제가 있는지 알 수 있고 error handling도 가능 !
const url = "https://jsonplaceholder.typicode.com/todos";
fetch(url)
.then((response) => {
if (!response.ok) {
throw new Error(
`This is an HTTP error: The status is ${response.status}`
);
}
return response.json();
})
.then(console.log)
.catch((err) => {
console.log(err.message);
});
fetch의 경우, catch()가 발생하는 경우는 오직 네트워크 장애 케이스
=> 따라서 개발자가 일일히 then() 안에 모든 케이스에 대한 HTTP 에러 처리를 해야함
intercept : 가로채다
interceptor : 가로채는 것 (?)

예를 들어 호출하는 서버 포트가 변경되었을 때, 만약 리액트 앱이 300개라면 …? 300개를 일일이 찾아서 변경해줘야 함 => 인적 리소스 낭비
axios interceptor : 즉, 클라이언트와 서버 사이의 axios interceptor는 요청(request)과 응답(response)의 흐름을 가로채서 코드에 관여를 하는 것 !!!
axios interceptor를 사용하면 아래 이러한 작업들을 한꺼번에 처리할 수 있음
.env (environment) : 환경변수 관리로 API key, port, DB 등 민감한 정보를 환경변수에 담아 관리하는 방법
env 주의사항
=> 즉, .env 파일을 이용해서 REACT_APP_SERVER_URL=http://localhost:4001 이런식으로 서버 URL 변수를 만들어줌
그리고 이제 App.jsx에서는 process.env.REACT_APP_SERVER_URL 이런 방식을 통해 URL에 접근할 수 있음
axios 폴더와 api.js 파일에서 axios를 가공해서 사용 !
=> axios.create()를 통해 새로운 instance를 만들어서 사용하면 됨, 그리고 create() 인자에는 객체가 들어감
가공하고 나서부터는 import api from "./axios/api"; 이런 식으로 import해서 api를 사용하여 접근하면 됨
instance.interceptors.request.use()
instance.interceptors.request.use(
// 요청을 보내기 전 수행되는 함수
// 인자로 항상 config를 받음
function (config) {
console.log("인터셉터 요청 성공 !");
return config;
},
// 오류 요청을 보내기 전 수행되는 함수
function (error) {
console.log("인터셉터 요청 오류 !");
// error 객체를 인자로 전달 ...
return Promise.reject(error);
}
);
instance.interceptors.response.use()
instance.interceptors.response.use(
// 응답을 내보내기 전 수행되는 함수
function (response) {
console.log("인터셉터 응답 성공 !!");
return response;
},
// 오류 응답을 내보내기 전 수행되는 함수
function (error) {
console.log("인터셉터 응답 오류 !!");
return Promise.reject(error);
}
);
실패 시켜보기
// timeout 프로퍼티
// 0.001초 동안 response가 안오면 무조건 오류를 낼 거야
timeout: 1, // message : "timeout of 1ms exceeded"
더 적용할 수 있는 부분