ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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": "시원하고 달달해서 참 좋다",
        }
      ]
    }

    db.json 파일 위치 및 내용

     

    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. 좋아하는것 수정해보기

    1. 좋아하는것 수정 후 새로고침 해서 데이터 업데이트됐는지 확인해보기
    2. 수정 후 바로 반영되게 변경해보기(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

    댓글

Designed by Tistory.