-
06. API 통신프론트엔드/React 2020. 1. 25. 01:00반응형SMALL
# What? 이게 뭔데?
- Application Programming Interface, 응용 프로그램 프로그래밍 인터페이스)는 응용 프로그램에서 사용할 수 있도록, 운영 체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스를 뜻한다.
=> 백엔드랑 소통하는 통신소라 생각하면 편함.
- 프론트 : 백엔드야 사용자가 할일 저장하고싶다고 나한테 이런 데이터를 입력해줬어
- 백엔드 : 어어 그래 데이터에 문제 있는지 살펴보고 문제 없으면 데이터베이스에 저장할게. 문제 없네? 저장했어 이게 저장한 데이터야
- 프론트 : 어 고마워 나도 사용자한테 저장 잘됐다고 알려주고, 할일 목록에 할일 추가해놓을게
이런 대화를 API를 통해서 함.
# Why? 왜 쓰는데?
- 왜 이런 소통을 API를 통해서 하나? API는 모든 접속을 표준화하기 때문에 기계/운영체제 등과 상관없이 누구나 동일한 액세스를 얻을 수 있음. 즉 백엔드는 JAVA + 리눅스, 프론트는 JAVASCRIPT + 노드처럼 서로 다른 환경이라 하더라도 API를 통해서라면 문제 없이 소통 가능.
# How? 어떻게 쓰는데?
1. 가상 API 서버 세팅(실습을 위해 가상의 API 서버를 세팅)
$ npm install -g json-server
1) db.json 파일 생성 및 테스트데이터 1개 세팅해놓기(여기에 데이터들이 저장될 예정)
@db.json
{ "favorites": [ { "id": 1, "title": "수박", "reason": "시원하고 달달해서 참 좋다", } ] }
2) API 서버 실행하기(백엔드용 서버, 프론트용 서버 두 개 열기)
$ npm start
$ json-server db.json --port=5000
2. 가상 API 서버와 통신하기 위해 axios라는 패키지 설치
$ npm install --save axios
METHOD URL axios로 통신 보낼 때 좋아하는것 목록 GET /favorites axios.get("/favorites"); 좋아하는것 생성
(좋아하는것 = favorite)POST /favorites axios.post("/favorites", data); 좋아하는것 수정 PATCH or PUT /favorites/{고칠 favorite의 id} axios.patch("/favorites/1", data); 좋아하는것 조회 GET /favorites/{보고싶은 favorite의 id} axios.get("/favorites/1"); 좋아하는것 삭제 DELETE /favorites/{삭제하고픈 favorite의 id} axios.delete(/favorites/1"); 3. proxy 설정
- api 서버로 통신을 보낼 때 axios("http://localhost:5000/favorites");와 같이 앞에 "http://localhost:5000" 붙여줘야함. 매번 붙여주려면 귀찮으니까 package.json의 proxy라는걸 설정해서 api를 보내는 root url을 http://localhost:5000로 고정할 수 있음. 이러면 매번 앞에 root url 안적어줘도됨.
@package.json(package.json 설정 후 npm start 다시 해줘야 변경사항 적용됨)
{ "name": "react-course", "version": "0.1.0", "private": true, "dependencies": { "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.4.0", "@testing-library/user-event": "^7.2.1", "axios": "^0.19.2", "react": "^16.12.0", "react-dom": "^16.12.0", "react-scripts": "3.3.0" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": "react-app" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "proxy": "http://localhost:5000" // 여기가 핵심 }
# Practice 연습
1. 좋아하는것 목록을 받아와서 뿌려보기
@App.js
import React from 'react'; import Favorites from './Favorites'; function App() { return ( <div className="App"> <Favorites /> </div> ); } export default App;
@ Favorites.js
import React, {useEffect, useState} from 'react'; import axios from 'axios'; import Favorite from "./Favorite"; const Favorites = () => { let [favorites, setFavorites] = useState([]); /* 컴포넌트가 렌더링 되면 바로 좋아하는것 목록을 불러와 favorites 데이터를 설정하기 */ useEffect(() => { axios.get("/favorites") .then(response => { // 응답 데이터 형태 관찰해보기 console.log(response); setFavorites(response.data); }).catch(error => { console.log(error); alert("문제가 발생하였습니다."); }); }, []); return ( <div> {/* map으로 컴포넌트를 여러개 만들 때는 각 컴포넌트를 구별할 수 있는 유일한 key값을 넘겨줘야함. */} {favorites.map(favorite => <Favorite key={favorite.id} favorite={favorite}/>)} </div> ); }; export default Favorites;
@ Favorite.jsx
import React, {} from 'react'; const Favorite = ({favorite}) => { return ( <div> <p>좋아하는 것 : {favorite.name}</p> <p>좋아하는 이유 : {favorite.reason}</p> </div> ); }; export default Favorite;
2. 좋아하는것 생성해보기
@ Favorites.js
import React, {useEffect, useState} from 'react'; import axios from 'axios'; import Favorite from "./Favorite"; const Favorites = () => { let [favorites, setFavorites] = useState([]); let [form, setForm] = useState({ title: "", // 좋아하는것 이름 reason: "", // 좋아하는 이유 }); /* 컴포넌트가 렌더링 되면 바로 좋아하는것 목록을 불러와 favorites 데이터를 설정하기 */ useEffect(() => { axios.get("/favorites") .then(response => { // 응답 데이터 형태 관찰해보기 console.log(response); setFavorites(response.data); }).catch(error => { console.log(error); alert("문제가 발생하였습니다."); }); }, []); const changeForm = (event) => { setForm({ ...form, [event.target.name]: event.target.value }) }; const save = (event) => { event.preventDefault(); axios.post("/favorites", form) .then(response => { // 응답 데이터 형태 관찰해보기(저장한 data를 반환해줌) console.log(response); // 데이터를 저장한 후, todos 목록 전체를 다시 불러올 수도 있지만, // 기존 목록에 새로 생성된 todo만 추가해주는게 더 효율적 setFavorites([...favorites, response.data]); }).catch(error => { console.log(error); alert("문제가 발생하였습니다."); }); }; return ( <div> <form onSubmit={save}> <div> <input type="text" name="title" placeholder="좋아하는것" onChange={changeForm}/> </div> <div> <input type="text" name="reason" placeholder="좋아하는 이유" onChange={changeForm} /> </div> <button>좋아하는것 추가</button> </form> {/* map으로 컴포넌트를 여러개 만들 때는 각 컴포넌트를 구별할 수 있는 유일한 key값을 넘겨줘야함. */} {favorites.map(favorite => <Favorite key={favorite.id} favorite={favorite}/>)} </div> ); }; export default Favorites;
3. 좋아하는것 수정해보기
- 좋아하는것 수정 후 새로고침 해서 데이터 업데이트됐는지 확인해보기
- 수정 후 바로 반영되게 변경해보기(setState 활용)
* 삼항연산자 알고가기
- 조건 ? (조건이 참일 때 실행할 내용) : (조건이 거짓일 때 실행할 내용)
- 예제 1) 너는 남자냐 ? 그렇다면 남탕으로 들어가 : 아니라면 여탕으로 들어가
- 예제 2) 철수가 맞는지 확인해보기
let name = "철수"; name === "철수" ? alert("나 철수 맞아") : alert("아닌데요"); // "나 철수 맞아"가 alert됨
@ Favorites.js
import React, {useEffect, useState} from 'react'; import axios from 'axios'; import Favorite from "./Favorite"; const Favorites = () => { let [favorites, setFavorites] = useState([]); let [form, setForm] = useState({ title: "", // 좋아하는것 이름 reason: "", // 좋아하는 이유 }); /* 컴포넌트가 렌더링 되면 바로 좋아하는것 목록을 불러와 favorites 데이터를 설정하기 */ useEffect(() => { axios.get("/favorites") .then(response => { // 응답 데이터 형태 관찰해보기 console.log(response); setFavorites(response.data); }).catch(error => { console.log(error); alert("문제가 발생하였습니다."); }); }, []); const changeForm = (event) => { setForm({ ...form, [event.target.name]: event.target.value }) }; const save = (event) => { event.preventDefault(); axios.post("/favorites", form) .then(response => { // 응답 데이터 형태 관찰해보기(저장한 data를 반환해줌) console.log(response); // 데이터를 저장한 후, todos 목록 전체를 다시 불러올 수도 있지만, // 기존 목록에 새로 생성된 todo만 추가해주는게 더 효율적 setFavorites([...favorites, response.data]); }).catch(error => { console.log(error); alert("문제가 발생하였습니다."); }); }; return ( <div> <form onSubmit={save}> <div> <input type="text" name="title" placeholder="좋아하는것" onChange={changeForm}/> </div> <div> <input type="text" name="reason" placeholder="좋아하는 이유" onChange={changeForm} /> </div> <button>좋아하는것 추가</button> </form> {/* map으로 컴포넌트를 여러개 만들 때는 각 컴포넌트를 구별할 수 있는 유일한 key값을 넘겨줘야함. */} {favorites.map(favorite => <Favorite key={favorite.id} favorite={favorite} favorites={favorites} setFavorites={setFavorites}/>)} </div> ); }; export default Favorites;
@ Favorite
import React, {useState, Fragment} from 'react'; import axios from "axios"; const Favorite = ({favorite, setFavorites, favorites}) => { let [updateMode, setUpdateMode] = useState(false); // 수정모드 여부 let [form, setForm] = useState({ title: favorite.title, description: favorite.description }); const changeMode = () => { setUpdateMode(!updateMode); }; const changeForm = (event) => { setForm({ ...form, [event.target.name]: event.target.value }) }; const update = (event) => { event.preventDefault(); axios.patch("/favorites/" + favorite.id, form) .then(response => { // 응답 데이터 형태 관찰해보기(수정한 data를 반환해줌) console.log(response); // 부모로부터 받은 setFavorites 참조를 이용하여 부모의 setFavorites를 호출하여 favorites를 업데이트 setFavorites(favorites.map(favorite => { if(favorite.id === response.data.id) return response.data; return favorite; })); setUpdateMode(false); }).catch(error => { console.log(error); alert("문제가 발생하였습니다."); }); }; return ( <div> {updateMode ? ( <Fragment> <div> <input type="text" name="title" defaultValue={favorite.title} onChange={changeForm}/> </div> <div> <input type="text" name="reason" defaultValue={favorite.reason} onChange={changeForm}/> </div> <button onClick={update}>수정완료</button> <button onClick={changeMode}>취소</button> </Fragment> ) : ( <Fragment> <p>좋아하는 것 : {favorite.title}</p> <p>좋아하는 이유 : {favorite.reason}</p> <button onClick={changeMode}>수정</button> </Fragment> ) } </div> ); }; export default Favorite;
4. 좋아하는것 삭제해보기
* filter 알고가기
- filter는 배열의 요소들을 하나씩 검사해보면서 조건에 안맞는 요소는 빼버린 배열을 반환해줌.
- 숫자 배열에서 짝수인 숫자는 다 빼버리기
let numbers = [1,2,3,4,5]; numbers = numbers.filter(number => { if(number % 2 !== 0) return number; })
@ Favorite.js
import React, {useState, Fragment} from 'react'; import axios from "axios"; const Favorite = ({favorite, setFavorites, favorites}) => { let [updateMode, setUpdateMode] = useState(false); // 수정모드 여부 let [form, setForm] = useState({ title: favorite.title, description: favorite.description }); const changeMode = () => { setUpdateMode(!updateMode); }; const changeForm = (event) => { setForm({ ...form, [event.target.name]: event.target.value }) }; const update = (event) => { event.preventDefault(); axios.patch("/favorites/" + favorite.id, form) .then(response => { // 응답 데이터 형태 관찰해보기(수정한 data를 반환해줌) console.log(response); // 부모로부터 받은 setFavorites 참조를 이용하여 부모의 setFavorites를 호출하여 favorites를 업데이트 setFavorites(favorites.map(favorite => { if(favorite.id === response.data.id) return response.data; return favorite; })); setUpdateMode(false); }).catch(error => { console.log(error); alert("문제가 발생하였습니다."); }); }; const remove = () => { axios.delete("/favorites/" + favorite.id) .then(response => { // 응답 데이터 형태 관찰해보기 console.log(response); /* filter는 배열의 요소 중 본인이 명시한 조건을 만족하는 요소만 남긴 배열을 반환함 */ setFavorites(favorites.filter(favoriteData => { return favoriteData.id !== favorite.id; })); }).catch(error => { console.log(error); alert("문제가 발생하였습니다."); }); }; return ( <div> {updateMode ? ( <Fragment> <div> <input type="text" name="title" defaultValue={favorite.title} onChange={changeForm}/> </div> <div> <input type="text" name="reason" defaultValue={favorite.reason} onChange={changeForm}/> </div> <button onClick={update}>수정완료</button> <button onClick={changeMode}>취소</button> </Fragment> ) : ( <Fragment> <p>좋아하는 것 : {favorite.title}</p> <p>좋아하는 이유 : {favorite.reason}</p> <button onClick={changeMode}>수정</button> </Fragment> ) } <button type="button" onClick={remove}>삭제</button> </div> ); }; export default Favorite;
# Problem 과제
* 코드참고: https://github.com/ShinHyungJune/react-course/blob/course-6-api/src/App.js
LIST'프론트엔드 > React' 카테고리의 다른 글
08. Redux(리덕스) (0) 2020.02.04 07. 리액트 라우터(React Router) (0) 2020.02.04 05. Event (0) 2020.01.23 04. 상태관리(state) (0) 2020.01.23 03. props (0) 2020.01.17