#1. Axios
1. Axios의 개념
1) Axios란?
- Axios는 브라우저, Node.js를 위한 Promise API를 활용하는 HTTP 비동기 통신 라이브러리이다.
- 상대적으로 다른 HTTP 통신 라이브러리들과 비교해서 문서화가 잘 되어 있고, API가 다양하다.
- 프론트엔드와 백엔드의 통신을 쉽게 하기 위해 Ajax와 함께 많이 사용한다.
(JS에서 Axios 사용하기 https://chan-co.tistory.com/53)
※ 비동기 방식이란?
- 비동기 방식은 웹페이지를 리로드 하지 않고 데이터를 불러오는 방식이며, Ajax를 통해 서버에 요청을 한 후 멈춰있는게 아니라 프로그램은 계속 돌아간다는 의미를 내포하고 있다.
- 장점으로는 한번 요청한 리소스를 재요청할 경우 불필요한 리소스는 요청하지 않고, 필요한 부분만 불러와 사용할 수 있다.
2) Axios의 특징
- 운영 환경에 따라 브라우저의 XMLHttpRequest 객체 또는 Node.js의 HTTP API 사용.
- Promise(ES6) API 사용.
- 요청 및 응답 데이터 변환.
- HTTP 요청 취소 및 요청과 응답을 JSON 형태로 자동 변경.
3) Axios의 기본 구조
- Axios를 사용해서 GET, POST, PUT, DELETE 등의 메서드로 API 요청이 가능하다.
- GET : 데이터 조회
- POST: 데이터 입력(등록)
- PUT: 데이터 수정
- DELETE: 데이터 삭제
4) Axios 설치하기
yarn add axios
- 해당 리액트 프로젝트 폴더에서 터미널(명령프롬프트)를 통해 위 명령어를 입력하여 라이브러리를 설치한다.
import axios from 'axios';
- axios를 사용할 jsx 파일에서 import 해주면 사용 가능하다.
2. Axios 사용하기
1) 데이터 정의
- myschool.json
{
"department": [
{
"id": 101,
"dname": "컴퓨터공학과",
"loc": "1호관"
},
{
"id": 102,
"dname": "멀티미디어학과",
"loc": "2호관"
},
{
"id": 201,
"dname": "전자공학과",
"loc": "3호관"
},
{
"id": 202,
"dname": "기계공학과",
"loc": "4호관"
}
]
}
- json 파일에 사용할 정보들를 저장한다.
- App.jsx
import React, { memo, useCallback, useEffect, useRef, useState } from 'react';
import axios from 'axios';
const Department = () => {
// ----------------------------------------------------------------- hooks 정의 시작
// 화면에 표시할 상태값 (ajax로 받아올 json, 초기값을 빈 배열로 정의)
const [ department, setDepartment ] = useState([]);
// 검색 키워드 값 정의
const [ keyword, setKeyword ] = useState('');
// 삭제할 항목에 대한 id값을 저장하기 위한 상태값
const [ deleteId, setDeleteId ] = useState(-1);
// 수정할 항목에 대한 id값을 저장하기 위한 상태값
const [ updateId, setUpdateId ] = useState(-1);
// ----------------------------------------------------------------- hooks 정의 끝
return (
<div>
</div>
);
};
// 함수형 컴포넌트의 리렌더링 성능 최적화
export default memo(Department);
- 상단에 hook을 import 하고, useState를 통해 사용할 상태값들을 정의한다.
2) GET (데이터 가져오기)
- App.jsx
const Department = () => {
// ----------------------------------------------------------------- hooks 정의 시작
~
// ----------------------------------------------------------------- hooks 정의 끝
// ----------------------------------------------------------------- 데이터 호출 시작
// 페이지가 처음 열렸을 때와 검색어가 반영되었을 때 데이터를 받아온다
useEffect(() => {
const getDepartment = async () => {
try {
const response = await axios.get('http://localhost:3001/department', {
// 검색어가 있다면 dname 값으로 설정, 그렇지 않으면 정의 안함
params: keyword ? { dname: keyword } : null
});
setDepartment(department => response.data);
} catch(e) {
console.error(e);
}
}
getDepartment();
}, [keyword]);
// ----------------------------------------------------------------- 데이터 호출 끝
// ----------------------------------------------------------------- 검색 시작
// 검색어 입력 요소에 연결할 참조 변수
const myKeywordInput = useRef();
// 검색 버튼에 대한 클릭 이벤트
const onButtonClick = e => {
setKeyword(myKeywordInput.current.value);
};
// ----------------------------------------------------------------- 검색 끝
return (
<div>
{/* 검색기능 */}
<form>
<input type="text" name='keyword' ref={myKeywordInput} />
<button type='button' onClick={onButtonClick}>검색</button>
</form>
<hr />
{/* 데이터를 가져와 화면에 보여준다 */}
<table border='1'>
<thead>
<tr>
<th>학과번호</th>
<th>학과명</th>
<th>학과위치</th>
</tr>
</thead>
<tbody>
{department.length > 0 ? (
department.map((v,i) => {
return (
<tr key={v.id}>
<td>{v.id}</td>
<td>{v.dname}</td>
<td>{v.loc}</td>
</tr>
);
})
) : (
<tr>
<td colSpan='3' align='center'>검색결과가 없습니다.</td>
</tr>
)}
</tbody>
</table>
</div>
);
};
※ 출력결과
2) POST (데이터 입력)
- App.jsx
const Department = () => {
// ----------------------------------------------------------------- hooks 정의
~
// ----------------------------------------------------------------- hooks 정의 끝
// ----------------------------------------------------------------- 데이터 호출 시작
~
// ----------------------------------------------------------------- 데이터 호출 끝
// ----------------------------------------------------------------- 검색 시작
~
// ----------------------------------------------------------------- 검색 끝
// ----------------------------------------------------------------- 데이터 추가 시작
// form에서 submit 이벤트가 발생할 때 호출할 이벤트 핸들러
// -> 성능 최적화를 위해 useCallback 사용
const onDepartmentSave = useCallback((e) => {
// 버튼의 본 기능 차단 (페이지 이동 차단)
e.preventDefault();
// form 안에 있는 입력 요소의 값 추출
const setDname = e.target.dname.value;
const setLoc = e.target.loc.value;
const postDepartment = async () => {
let json = null;
try {
const response = await axios.post('http://localhost:3001/department', {
dname: setDname,
loc: setLoc
});
json = response.data;
} catch(e) {
console.error(e)
}
if(json !== null) {
// 기존의 상태값과 배열간 병합을 처리하기 위해 응답결과를 배열로 묶음
const addArr = [json];
// 배열 병함 결과로 상태값을 갱신함
setDepartment(department => department.concat(addArr));
}
};
postDepartment();
}, [])
// ----------------------------------------------------------------- 추가 끝
return (
<div>
{/* 검색기능 */}
...
{/* 저장기능 */}
<form onSubmit={onDepartmentSave}>
<label htmlFor="dname">학과: </label>
<input type="text" name='dname' id='dname' />
<label htmlFor="loc">위치: </label>
<input type="text" name='loc' id='loc' />
<button type='submit'>저장하기</button>
</form>
<hr />
{/* 데이터를 가져와 화면에 보여준다 */}
...
</div>
);
};
※ 출력결과
3) delete (데이터 삭제)
const Department = () => {
// ----------------------------------------------------------------- hooks 정의
~
// ----------------------------------------------------------------- hooks 정의 끝
// ----------------------------------------------------------------- 데이터 호출 시작
~
// ----------------------------------------------------------------- 데이터 호출 끝
// ----------------------------------------------------------------- 검색 시작
~
// ----------------------------------------------------------------- 검색 끝
// ----------------------------------------------------------------- 데이터 추가 시작
~
// ----------------------------------------------------------------- 데이터 추가 끝
// ----------------------------------------------------------------- 삭제 시작
// 삭제하기 버튼이 클릭되었을 때 호출할 이벤트 핸들러
const onDeleteClick = useCallback(e => {
// 클릭된 자기 자신
// const current = e.target;
// 클릭된 자신에게 숨어 있는 data-id값 추출
const id = parseInt(e.target.dataset.id);
// 삭제 대상임을 알림
setDeleteId(id);
}, []);
// deleteId가 변경되었을 때 실행할 hook
useEffect(() => {
if(deleteId > -1) {
// id가 일치하지 않는 항목만 filter로 걸러내어 상태값 갱신 (같지 않은 모든 항목을 리턴)
// 성능향상을 위해 상태값을 함수형 업데이트로 처리함
// -> 상태값을 파라미터로 받는 콜백에서 상태값 생신 결과를 리턴
setDepartment(department => department.filter((v,i) => v.id !== deleteId));
// TODO: 백엔드에 삭제 요청
const deleteDepartment = async () => {
try {
// ajax를 통한 데이터 삭제 요청
await axios.delete(`http://localhost:3001/department/${deleteId}`);
} catch(e) {
console.error(e);
}
};
deleteDepartment();
// 상태변수 원래 상태로 돌리기
setDeleteId(-1);
}
}, [deleteId]);
// ----------------------------------------------------------------- 삭제 끝
return (
<div>
{/* 검색기능 */}
...
{/* 저장기능 */}
...
{/* 데이터를 가져와 화면에 보여준다 */}
<table border='1'>
<thead>
<tr>
<th>학과번호</th>
<th>학과명</th>
<th>학과위치</th>
<th>삭제</th>
</tr>
</thead>
<tbody>
{department.length > 0 ? (
department.map((v,i) => {
return (
<tr key={v.id}>
<td>{v.id}</td>
<td>{v.dname}</td>
<td>{v.loc}</td>
<td>
<button type='button' data-id={v.id} onClick={onDeleteClick}>
삭제하기
</button>
</td>
</tr>
);
})
) : (
<tr>
<td colSpan='4' align='center'>검색결과가 없습니다.</td>
</tr>
)}
</tbody>
</table>
</div>
);
};
※ 출력결과
4) PUT (데이터 수정하기)
const Department = () => {
// ----------------------------------------------------------------- hooks 정의
~
// ----------------------------------------------------------------- hooks 정의 끝
// ----------------------------------------------------------------- 데이터 호출 시작
~
// ----------------------------------------------------------------- 데이터 호출 끝
// ----------------------------------------------------------------- 검색 시작
~
// ----------------------------------------------------------------- 검색 끝
// ----------------------------------------------------------------- 데이터 추가 시작
~
// ----------------------------------------------------------------- 데이터 추가 끝
// ----------------------------------------------------------------- 삭제 시작
~
// ----------------------------------------------------------------- 삭제 끝
// ----------------------------------------------------------------- 수정 시작
// 수정하기 버튼이 클릭되었을 때 호출할 이벤트 핸들러
const onUpdateClick = useCallback(e => {
e.preventDefault();
// 수정할 항목에 대한 인덱스 번호를 상태값으로 설정한다.
setUpdateId(parseInt(e.target.dataset.id));
}, []);
// 수정에 대한 저장 버튼이 클릭되었을 때 호출될 이벤트 핸들러
const onUpdateSubmit = useCallback(e => {
e.preventDefault();
// form 요소 내의 input 요소들을 name 속성값으로 접근하여 입력값을 얻는다.
const setId = e.target.id.value;
const setDname = e.target.dname.value;
const setLoc = e.target.loc.value;
// 백엔드에 데이터 수정 요청
const putDepartment = async () => {
try {
const response = await axios.put(`http://localhost:3001/department/${setId}`, {
dname: setDname,
loc: setLoc,
});
// 함수형 업데이트
// -> 콜백함수의 파라미터로 상태값의 복사본이 전달되므로 이 값을 직접 수정해도 된다.
setDepartment(department => {
// 원본 상태값과 비교하여 수정된 항목의 배열 인덱스를 찾는다.
const find = department.findIndex((v,i) => v.id === response.data.id);
// 원본 상태값의 해당 인덱스 번호(find) 위치 부터 1개를 ajax로 반환받은 수정결과 데이터로 교체한다.
department.splice(find, 1, response.data);
return department;
});
} catch(e) {
console.error(e);
}
}
putDepartment();
// 상태변수 되돌리기
setUpdateId(-1);
}, []);
// ----------------------------------------------------------------- 수정 끝
return (
<div>
{/* 검색기능 */}
...
{/* 저장기능 */}
...
{/* 데이터를 가져와 화면에 보여준다 */}
<form onSubmit={onUpdateSubmit}>
<table border='1'>
<thead>
<tr>
<th>학과번호</th>
<th>학과명</th>
<th>학과위치</th>
<th>수정</th>
<th>삭제</th>
</tr>
</thead>
<tbody>
{department.length > 0 ? (
department.map((v,i) => {
return(
<tr key={v.id}>
{/* 상태값에 저장되어 있는 수정할 항목의 인덱스에 해당하는 원소라면? */}
{updateId === v.id ? (
<>
{/* 수정을 위한 input 요소를 표시 */}
<td><input type="hidden" name='id' defaultValue={v.id} />{v.id}</td>
<td><input type="text" name='dname' defaultValue={v.dname} /></td>
<td><input type="text" name='loc' defaultValue={v.loc} /></td>
<td colSpan='2' align='center'>
<button type='submit'>저장</button>
</td>
</>
) : (
<>
{/* 데이터를 텍스트로 출력 */}
<td>{v.id}</td>
<td>{v.dname}</td>
<td>{v.loc}</td>
<td>
<button type='button' data-id={v.id} onClick={onUpdateClick}>
수정하기
</button>
</td>
<td>
<button type='button' data-id={v.id} onClick={onDeleteClick}>
삭제하기
</button>
</td>
</>
)}
</tr>
);
})
) : (
<tr>
<td colSpan='5' align='center'>
검색결과가 없습니다.
</td>
</tr>
)}
</tbody>
</table>
</form>
</div>
);
};
※ 출력결과
'국비수업 > React' 카테고리의 다른 글
[React/Redux] Redux (0) | 2022.05.20 |
---|---|
[React] Axios-hooks (0) | 2022.05.17 |
[React] Hooks (0) | 2022.04.29 |
[React] CSS 사용하기 (0) | 2022.04.26 |
[React] Props (Properties) (0) | 2022.04.25 |