http를 이용해서 서버와 통신하기 위해 사용하는 패키지
https://axios-http.com/kr/docs/req_config
요청 Config | Axios Docs
요청 Config 다음은 요청을 만드는 데 사용할 수 있는 config 옵션들 입니다. 오직 url만 필수입니다. method를 지정하지 않으면 GET방식이 기본값 입니다. { url: '/user', method: 'get', baseURL: 'https://some-domain.
axios-http.com
설치
yarn add axios
테스트용 json-server랑 사용할거면
https://console-log.tistory.com/149
환경변수 적용
환경변수 적용할 땐 대신 서버를 껐다켜야 반영됨.
깃헙에 올리면 안됨
(./env)
REACT_APP_SERVER_URL=http://localhost:4000
사용법
GET
axios.get(url[, config])
// 조회 함수
// db로부터 값을 가져오기 위해선 비동기 함수를 만들거. 서버 통신 자체가 비동기 통신
const fetchTodos = async () => {
// 응답을 받을 때까지 기다리도록 await 키워드 추가
// 안에 들은 data 부분만 받아오려고 구조분해할당
// 환경변수 적용함
const { data } = await axios.get(`${process.env.REACT_APP_SERVER_URL}/todos`);
setTodos(data);
};
POST
axios.post(url[, data[, config]])
// 추가 함수
// 변수이름이 서브밋을 눌렀을때 발생하는 핸들러라는 뜻으로 지어줌
// post 요청을 하는거니까 async함수
const onSubmitHandler = async () => {
// axios.post('http://localhost:4000/todos', inputValue);
// 환경변수 적용
await axios.post(`${process.env.REACT_APP_SERVER_URL}/todos`, inputValue);
// 컴포넌트가 렌더링되는 조건: 1.state 2.props 3.부모컴포넌트
// state가 안변해서 렌더링이 안되기때문에
// 그래서 todos도 바꿔줘야 됨
// setTodos([...todos, inputValue]);
// state에서는 db에서 자동으로 생성되는 id값을 알 수 없으니까 다시 DB를 읽어오는 방식이 적합할 수 있음
fetchTodos();
};
DELETE
axios.delete(url[, config])
// 삭제 함수
// 클릭되면 axios를 통해서 삭제가 되어야하기 떄문에 어씽크함수. 몇번째 아이템이 삭제되는지 id를 알려줘야 함
const onDeleteButtonClickHandler = async (id) => {
axios.delete(`${process.env.REACT_APP_SERVER_URL}/todos/${id}`);
// 마찬가지로 state도 바꿔서 렌더링되게 해줘야함
// filter 사용하면 됨
setTodos(
todos.filter((item) => {
return item.id !== id;
})
);
};
PATCH
axios.patch(url[, data[, config]])
// 수정 함수
const onUpdateButtonClickHandler = async () => {
// await 왜 안씀?? -> setTodos로 렌더링 시켜줄거라?
axios.patch(`${process.env.REACT_APP_SERVER_URL}/todos/${targetId}`, {
title: contents,
});
setTodos(
todos.map((item) => {
if (item.id == targetId) {
return { ...item, title: contents };
} else {
return item;
}
})
);
};
axios interceptor
요청과 응답의 중간부분에서 가로채서 어떠한 역할을 하는게 인터셉터
- 요청 헤더 추가. request header에 content-type 적용
- 인증 관리: token 등 인정 관련 로직 적용
- 로그 관련 로직 삽입
- 에러 핸들링: 서버 응답 코드에 대한 오류 처리(controller)
- 통신시작 및 종료에 대한 전역 상태를 관리하여 spinner, progress bar 등 구현 가능
(src/axios/api.js)
import axios from 'axios';
// create 인자로 configuration관련 객체가 들어감 (https://axios-http.com/docs/req_config)
// 무슨 인자를 기본으로 url을 달고 호출할꺼냐 baseURL
const instance = axios.create({
baseURL: process.env.REACT_APP_SERVER_URL,
// timeout: 1,
});
// timeout 나는 언제까지 기다릴꺼야 하는 초(ms) 단위. 1000이 1초
// timeout: 1 // 강제로 오류내기
// request, response에 적용해보기
// ⭐ 요청할때 content타입에 대해 지정을 하거나,
// 토큰에 관련된 인증을 삽입하거나, 서버 응답에 대한 오류처리,
// 통신의 시작과 종료에 대한 전역상태를 관리해서 스피너나 프로그레스바를 관리할 수 있음
// 인터셉터를 적극 활용해서 고도화~
// 인자로 2개의 함수가 항상 들어감
instance.interceptors.request.use(
// 요청을 보내기 전 수행되는 함수
// 항상 config라는 인자를 받음
function (config) {
console.log('인터셉터 요청 성공!');
return config;
},
// 오류 요청을 보내기 전 수행되는 함수
function (error) {
console.log('인터셉터 요청 오류!');
return Promise.reject(error);
}
);
instance.interceptors.response.use(
// 응답을 내보내기 전 수행되는 함수
function (response) {
console.log('인터셉터 응답 받았습니다.');
return response;
},
// 오류응답을 내보내기 전 수행되는 함수
function (error) {
console.log('인터셉터 응답 오류!');
return Promise.reject(error);
}
);
export default instance;
(App.jsx)
import { useEffect, useState } from 'react';
import api from './axios/api';
function App() {
const [todos, setTodos] = useState(null);
// JSON방식의 디비는 아이디 속성은 자동으로 입력됨. title같은거만 포스트로 보내주면 id는 자동처리 해줌
const [inputValue, setInputValue] = useState({
title: '',
});
const [targetId, setTargetId] = useState('');
const [contents, setContents] = useState('');
// 조회 함수
const fetchTodos = async () => {
const { data } = await api.get('/todos');
// console.log('data', data);
setTodos(data);
};
// 추가 함수
const onSubmitHandler = async () => {
// 인터셉터 적용
await api.post('/todos', inputValue);
fetchTodos();
};
// 삭제 함수
const onDeleteButtonClickHandler = async (id) => {
await api.delete(`/todos/${id}`);
setTodos(
todos.filter((item) => {
return item.id !== id;
})
);
};
// 수정 함수
const onUpdateButtonClickHandler = async () => {
await api.patch(`/todos/${targetId}`, {
title: contents,
});
setTodos(
todos.map((item) => {
if (item.id == targetId) {
return { ...item, title: contents };
} else {
return item;
}
})
);
};
useEffect(() => {
// 1. db로부터 값을 가져올 것이다.
fetchTodos();
}, []);
// 데이터가 비동기이기 때문에 아래 return 부분이 기다려주지 않고 먼저 실행되서 오류가 남. 따라서 옵셔널 체이닝 사용. todos?.map ...
return (
<div>
<section>
{/* 수정 영역 */}
<input
type="text"
placeholder="수정할 아이디"
value={targetId}
onChange={(e) => {
setTargetId(e.target.value);
}}
/>
<input
type="text"
placeholder="수정할 내용"
value={contents}
onChange={(e) => {
setContents(e.target.value);
}}
/>
{/* 넘겨줄 내용 없으니까 인자로 안쓰고 아래처럼 핸들러를 연결해주면 됨 */}
<button onClick={onUpdateButtonClickHandler}>수정</button>
</section>
<br></br>
<br></br>
<section>
{/* INPUT 영역 */}
{/* form 태그 안의 button은 기본적으로 submit속성을 가지고 있어서 누르면 새로고침이 됨. 그래서 새로고침을 막기 위해 form태그에서 onSubmit으로 event.preventDefault()처리해서 막아줘야 됨~ */}
<form
onSubmit={(e) => {
e.preventDefault();
// 버튼 클릭 시, input에 들어있는 값(state)를 이용하여 DB에 저장(post 요청)
onSubmitHandler();
}}
>
<input
type="text"
value={inputValue.title}
onChange={(e) => {
setInputValue({ title: e.target.value });
}}
/>
<button>추가</button>
</form>
</section>
<section>
{/* 데이터 영역 */}
{todos?.map((item) => {
return (
<div key={item.id}>
{item.id} : {item.title}
{/* onClick={onDeleteButtonClickHandler(item.id)}으로 하면 인자로 보낼 때 함수가 실행되어버리기 때문에 함수로 한 번 더 감싸줘야 함 */}
<button onClick={() => onDeleteButtonClickHandler(item.id)}>삭제</button>
</div>
);
})}
</section>
</div>
);
}
export default App;
개발자도구 네트워크탭 확인하기
네트워크 쪽 개발을 할 때는
브라우저의 네트워크 탭에서 어떤 로그가 생기는지 확인하면서 개발을 진행해야 함
빨간점 옆에 금지 아이콘 누르면 clear됨
fetch/XHR에서 확인
- headers: URL, 메서드, 상태 코드 등을 확인할 수 있음
- payload: 우리가 보낸 body를 확인할 수 있음
- response: 우리가 보낸 요청에 대한 서버의 응답값을 확인할 수 있음.
import { useEffect, useState } from 'react';
import './App.css';
import axios from 'axios';
function App() {
const [todos, setTodos] = useState(null);
// JSON방식의 디비는 아이디 속성은 자동으로 입력됨. title같은거만 포스트로 보내주면 id는 자동처리 해줌
const [inputValue, setInputValue] = useState({
title: '',
});
const [targetId, setTargetId] = useState('');
const [contents, setContents] = useState('');
// 조회 함수
// 2. db로부터 값을 가져오기 위해선 비동기 함수를 만들거. 서버 통신 자체가 비동기 통신
const fetchTodos = async () => {
// 응답을 받을 때까지 기다리도록 await 키워드 추가
// 안에 들은 data 부분만 받아오려고 구조분해할당
const { data } = await axios.get('http://localhost:4000/todos');
setTodos(data);
};
// 추가 함수
// 변수이름이 서브밋을 눌렀을때 발생하는 핸들러라는 뜻으로 지어줌
// post 요청을 하는거니까 async함수
const onSubmitHandler = async () => {
// axios.post('http://localhost:4000/todos', inputValue);
// 환경변수 적용
// axios.post(`${process.env.REACT_APP_SERVER_URL}/todos`, inputValue);
// 컴포넌트가 렌더링되는 조건: 1.state 2.props 3.부모컴포넌트
// state가 안변해서 렌더링이 안되기때문에
// 그래서 todos도 바꿔줘야 됨
// setTodos([...todos, inputValue]);
// state에서는 db에서 자동으로 생성되는 id값을 알 수 없으니까 다시 DB를 읽어오는 방식이 적합할 수 있음
fetchTodos();
};
// 삭제 함수
// 클릭되면 axios를 통해서 삭제가 되어야하기 떄문에 어씽크함수. 몇번째 아이템이 삭제되는지 id를 알려줘야 함
const onDeleteButtonClickHandler = async (id) => {
// await axios.delete(`${process.env.REACT_APP_SERVER_URL}/todos/${id}`);
await api.delete(`/todos/${id}`);
// 마찬가지로 state도 바꿔서 렌더링되게 해줘야함
// filter 사용하면 됨
setTodos(
todos.filter((item) => {
return item.id !== id;
})
);
};
// 수정 함수
const onUpdateButtonClickHandler = async () => {
// await 왜 안씀??
await api.patch(`/todos/${targetId}`, {
title: contents,
});
setTodos(
todos.map((item) => {
if (item.id == targetId) {
return { ...item, title: contents };
} else {
return item;
}
})
);
};
useEffect(() => {
// 1. db로부터 값을 가져올 것이다.
fetchTodos();
}, []);
// 데이터가 비동기이기 때문에 아래 return 부분이 기다려주지 않고 먼저 실행되서 오류가 남. 따라서 옵셔널 체이닝 사용. todos?.map ...
return (
<div>
<section>
{/* 수정 영역 */}
<input
type="text"
placeholder="수정할 아이디"
value={targetId}
onChange={(e) => {
setTargetId(e.target.value);
}}
/>
<input
type="text"
placeholder="수정할 내용"
value={contents}
onChange={(e) => {
setContents(e.target.value);
}}
/>
{/* 넘겨줄 내용 없으니까 인자로 안쓰고 아래처럼 핸들러를 연결해주면 됨 */}
<button onClick={onUpdateButtonClickHandler}>수정</button>
</section>
<br></br>
<br></br>
<section>
{/* INPUT 영역 */}
{/* form 태그 안의 button은 기본적으로 submit속성을 가지고 있어서 누르면 새로고침이 됨. 그래서 새로고침을 막기 위해 form태그에서 onSubmit으로 event.preventDefault()처리해서 막아줘야 됨~ */}
<form
onSubmit={(e) => {
e.preventDefault();
// 버튼 클릭 시, input에 들어있는 값(state)를 이용하여 DB에 저장(post 요청)
onSubmitHandler();
}}
>
<input
type="text"
value={inputValue.title}
onChange={(e) => {
setInputValue({ title: e.target.value });
}}
/>
<button>추가</button>
</form>
</section>
<section>
{/* 데이터 영역 */}
{todos?.map((item) => {
return (
<div key={item.id}>
{item.id} : {item.title}
{/* onClick={onDeleteButtonClickHandler(item.id)}으로 하면 인자로 보낼 때 함수가 실행되어버리기 때문에 함수로 한 번 더 감싸줘야 함 */}
<button onClick={() => onDeleteButtonClickHandler(item.id)}>삭제</button>
</div>
);
})}
</section>
</div>
);
}
export default App;'React' 카테고리의 다른 글
| Custom Hooks (0) | 2023.07.06 |
|---|---|
| Thunk (0) | 2023.07.06 |
| json-server (0) | 2023.07.06 |
| Redux Devtools (0) | 2023.07.06 |
| Redux Toolkit (0) | 2023.07.06 |