Pages파일 밑에 Board.jsx생성
url파라미터 예제
function Board(props){
const boardSelect = useParams();
return(
<div>
<h2>글번호 : {boardSelect.boardIdx}</h2>
</div>
)
}
App7.jsx
<Route path = {"board/:boardIdx"} element={<Board/>}/>
쿼리스트링
// Board2.jsx
// 쿼리스트링 예제
import React from "react";
import {useLocation, useSearchParams} from "react-router-dom";
function Board2(props) {
const param1 = useLocation();
const [param2, setParam2] = useSearchParams();
return(
<div>
<p>{param1.search}</p>
<p>{param2.get("val1")}</p>
<p>{param2.get("val2")}</p>
</div>
)
}
export default Board2;
board2.jsx에 삽입
<button className={'btn btn-primary'} onClick={goBack}>뒤로 이동</button>
<button className={'btn btn-success'} onClick={goBoard}>Board 페이지로 이동(1번,100)</button>
// Board2.jsx
// 쿼리스트링 예제
import React from "react";
import {useLocation, useNavigate, useNavigation, useSearchParams} from "react-router-dom";
function Board2(props) {
const param1 = useLocation();
const [param2, setParam2] = useSearchParams();
// useNavigate() 예제
const navi = useNavigate();
const goBack = () =>{
navi(-1);
}
const goBoard = () => {
navi('/Board/100')
}
return(
<div>
<p>{param1.search}</p>
<p>{param2.get("val1")}</p>
<p>{param2.get("val2")}</p>
{/* navi위한 버튼*/}
<button className={'btn btn-primary'} onClick={goBack}>뒤로 이동</button>
<button className={'btn btn-success'} onClick={goBoard}>Board 페이지로 이동(1번,100)</button>
</div>
)
}
export default Board2;
board페이지로 이동 누르면 아래와 같이 된다.
react.test2(내 기준) 쌤 java505_react_test1
promise.jsx 배웠던 것. 비동기인걸 동기인 것처럼 실행
// resolve 하면 then 실행됨
// reject 하면 catch 실행됨
// 프로미스 사용 후 결과를 출력 // 함수 실행
getData()
.then(function (data){
console.log(`프로미스 사용 반환 값 : ${data}`);
})
.catch(function (err){
console.log(`프로미스 사용 오류 시 출력 : ${err}`);
});
const getData1 = function () {
return new Promise(function (resolve, reject){
// import $ from "jquery"; 이거 있어야합!!
$.ajax({
url: 'http://localhost:8080/async/data1',
type : 'post',
success: function (data){
console.log('통신성공');
resolve(data);
},
error : function (){
reject('오류발생!!');
}
});
});
};
function App() {
getData();
getData1()
.then(function(data) {
console.log(data);
})
.catch(function (err){
console.log(err);
})
return (
<div className="App">
</div>
);
}
//App7.jsx
import React from "react";
import Culculator from "./folder4/Culculator";
import App from "./folder4/App";
import App2 from "./folder4/App2";
import App4 from "./folder4/App4";
import DarkOrLight from "./folder4/DarkOrLight";
// 라우터 추가된 후 추가된 부분
import {BrowserRouter,Routes, Route} from "react-router-dom";
import Layout from "./Pages/Layout";
import Home from "./Pages/Home";
import Blogs from "./Pages/Blogs";
import Contact from "./Pages/Contact";
import NoPage from "./Pages/NoPage";
import Board from "./Pages/Board";
import Board2 from "./Pages/Board2";
function App7() {
return (
// <div>
// <Culculator />
// <App/>
// <hr/>
// <App2/>
// <hr />
// <DarkOrLight/>
// <App4/>
// </div>
// 리액트 라우터 : spa방식의 리액트 앱을 mpa방식으로 사용할 수 있도록 해주는 라이브러리
// Routes : 페이지 객체를 여러 개 가질 수 있는 객체
// Route : 화면에 그려지는 페이지 객체
// Path : 웹 브라우저에 표시되는 url 주소 설정, 절대 경로/상대경로 다 사용 가능,
// * 사용시 모든 페이지를 뜻함.(path url을 정확하게 입력해야 접속이 가능하다.)
// element : path로 지정된 url 주소와 매칭되는 컴포넌트 (localhost : 3030)
// <Link> : 리액트 라우터에서 사용되는 링크 전용 컴포넌트, html의 <a>태그와 같다.
// to : url 주소 입력, Route 컴포넌트에 path로 설정된 주소
// <Outlet> : 현재 선택된 경로의 컴포넌트를 화면에 표시
// 2023 01 10
// url 파라미터 : restful 방식의 주소형태로 구성되는 파라미터
// 기존 url 뒤에 /와 :파라미터명을 사용하여 데이터를 전달하는 방식
// rest 방식에서 많이 사용함
// 연결된 컴포넌트에서 useParams 훅을 사용해야 한다.
// 사용법 :
// 기존url/:파라미터1/:파라미터2
// <Route path = url/:test1/:test2 element={<Url/>}>
// 쿼리스트링 : 기존의 get 방식으로 웹 브라우저의 주소에 파라미터를 함께 전달하는 방식
// <Route > 컴포넌트의 path에 변경이 없다
// 지정된 컴포넌트에서 몇 가지 옵션 사항을 사용할 수 있다.
// 옵션 :
// pathname : 쿼리 스트링을 제외한 현재 주소의 경로
// search : 맨 앞의 ? 문자를 포함한 쿼리스트링 값 전체가 출력
// hash : 주소의 # 문자열 뒤의 값 (구형 브라우저에서만 사용)
// state : 페이지 이동 시 임의로 추가한 상태 값
// key : location 객체의 고유값
// useLocation(), useSearchParams() 훅을 사용하여 데이터를 가져올 수 있다
// useLocation()훅을 사용하여 데이터를 가져오면 원하는 파라미터 값을 가져오기 위해 직접 파싱을 진행해야 함.
// useSearchParams() 훅을 사용하여 데이터를 가져오면 파라미터 데이터만 따로 가져올 수 있다
// 사용법 :
// 기존 url?파라미터1=값1%파라미터2=값2
//
// useNavigate() : Link 컴포넌트를 사용하지 않고 다른 페이지로 이동하는 훅
// 사용법 :
// const navigate = useNavigate();
// navigate(-1) // History를 사용하여 뒷페이지로 이동(js기억나쥬??), 숫자를 음수로 입력 시 해당 뒤로 이동
// 양수로 입력 시 앞으로 이동
// navigate('/url') //지정한 url로 이동
//
// 페이지 넘어갈 수 있게
<BrowserRouter>
<Routes>
{/*Route path={"/"}는 모든 주소가 /밑에 적힌다는 의미이다.*/}
<Route path={"/"} element={<Layout/>}>
<Route index element={<Home/>}/>
<Route path={"blogs"} element={<Blogs />}/>
<Route path={"contact"} element={<Contact />}/>
<Route path={"*"} element={<NoPage />}/>
<Route path = {"board/:boardIdx"} element={<Board/>}/> {/*url파라미터*/}
<Route path = {"board2"} element={<Board2 />}/> {/*쿼리스트링*/}
</Route>
</Routes>
</BrowserRouter>
);
}
export default App7;
https://axios-http.com/kr/docs/intro
프로미스 기반 비동기 통신
설치해야 한다.
npm install axios
터미널 창에 입력
folder5/AxiosTest.jsx
https://www.kobis.or.kr/kobisopenapi/homepg/main/main.do
영화진흥원api 가져온다
위에 날짜를 바꾸면 어제 꺼 확인 가능하다.
좀 더 쉽게 api를 가져올 수 있다
console.log(req.data.boxOfficeResult.dailyBoxOfficeList);
// AsyncAwait.jsx
import React from "react";
import axios, {Axios} from "axios";
// async / await : 비동기 처리를 조금 더 쉽게 하기 위해서 개발됨
// 기본적으로 promise를 사용함
// 사용법 :
// async funciton 함수명(매개변수) {
// const 변수명 = await promise를 사용하는 함수();
// const.log(변수명);
// }
function AsyncAwait(props){
const fetchItems = () => {
return new Promise((resolve, reject) => {
var items = [1,2,3];
resolve(items);
});
}
// 프로미스 사용 시 비동기 처리방법
const logItem1 = () => {
//프로미스를 반환하는 함수를 직접 호출해야한다
fetchItems()
.then((item) => {
console.log(item);
})
.catch((err) => {
console.log(err);
});
}
// async / await 사용 시 비동기 처리방식
const logItem2 = async () => {
const resultItems = await fetchItems();
// 이렇게 해도 된다
// resultItems
// .then(() => {
//
// })
// .catch(()=>{
//
// });
console.log(resultItems);
}
//axios사용
const getData = async () => {
// await 비동기가 끝날 때까지 기다렸다가 실행
const {data} = await axios.get('https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList' +
'.json?key=f5eef3421c602c6cb7ea224104795888&targetDt=20230109');
console.log(data.boxOfficeResult.dailyBoxOfficeList);
}
return(
<div>
{/*둘의 결과값은 동일. */}
<button className={"btn btn-primary"} onClick={logItem1}>프로미스 사용</button>
<button className={"btn btn-success"} onClick={logItem2}>async/await 사용</button>
<button className={"btn btn-info"} onClick={getData}>axios와 함께 사용하기</button>
</div>
)
}
export default AsyncAwait;
import React, {useEffect} from "react";
import axios from "axios";
// AxiosTest.jsx
// axios : node.js에서 비동기 통신을 하기 위한 라이브러리, promise를 사용함 (then,catch있다)
// axios는 rest 방식을 지원한다
// get(url) : get 방식으로 서버에 데이터를 요청
// post(url, data[, config]) : post 방식으로 서버에 데이터를 전달
// put(url, data[, config]) : put 방식으로 서버에 데이터 전달
// delete(url, data[,config]) : delete 방식으로 데이터 전달
// options(url, config) : axios 객체 생성 시 설정 정보를 변경할 수 있음
// then() : 정상적으로 통신이 성공했을 경우 실행
// catch() : 통신이 실패했을 경우 실행된다
// async/await 와 함께 사용 시 then()을 필요한 경우 나중에 호출할 수 있음
// async/await 와 함께 사용 시 예외처리를 try/catch로 처리한다
// 응답 객체 : 요청에 대한 응답 객체가 json 방식으로 전달됨
// data{} : 서버에서 제공한 데이터 json 타입
// status : 서버와의 통신 응답 신호, 200 : ok, 300 : redirect, 400 : 리소스없음, 500 : 서버 내부 오류
// statusText : 서버와의 응답 메시지
// headers{} : 서버에서 응답한 헤더 정보
// config{} : 서버에 요청 시 axios의 설정 정보
// request{} : 응답을 생성한 요청
// 사용법 :
// npm install axios; // 사용할 프로젝트 axios 설치
// import axios from 'axios'; // 사용할 컴포넌트에서 axios import
// axios({
// method : 'get|post|put|delete',
// url : 'url',
// data : {
// param1 : 'data',
// param2 : 'data'
// },
// });
// 보통은 이거 사용하는 편이다.
// axios.get(url)
// .then(function(rep)){
// 성공 시 실행할 소스;
// });
// .catch(function(err)){
// 실패 시 실행할 소스;
// });
// axios.post(url, {
// param1: 'data1',
// param2: 'data2'
// })
// .then(function(req){
// 성공 시 실행할 소스;
// })
// .catch(function(err){
// 실패 시 실행할 소스;
// })
//
function AxiosTest(props){
useEffect(()=>{
//영화진흥원 api 가져왔다 json방식
axios.get('https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.' +
'json?key=f5eef3421c602c6cb7ea224104795888&targetDt=20230109')
.then((req)=>{
// alert('통신성공')
console.log('통신성공')
// console.log(req);
// console.log(req.data);
console.log(req.data.boxOfficeResult.dailyBoxOfficeList);
const list = req.data.boxOfficeResult.dailyBoxOfficeList;
// console.log(dailyBoxOfficeList);
for(let i =0; i<list.length; i++){
let str = `순번 : ${list[i].rnum}`
console.log(`순번 : ${list[i].rnum}
순위 : ${list[i].rank}
제목 : ${list[i].movieNm}
개봉일 : ${list[i].openDt}
관람객 : ${list[i].audiCnt}`)
}
})
.catch((err)=>{
alert('통신실패')
});
},[]);
return(
<div>
</div>
)
}
export default AxiosTest;
//DailyBoxOffice.jsx
// 클릭하면 작동하도록
import React, {useState} from "react";
import axios from "axios";
// 문제 1) 버튼 클릭 시 axios 통신을 통해 데이터를 가져와서 화면의 table에 출력하는 컴포넌트를 작성하세요
function DailyBoxOffice(props){
// 초기값이 빈 배열이라는 것이 중요하다
const [boxOffice, setBoxOffice] = useState([]);
const loadBoxOffice = () =>{
axios.get('https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList' +
'.json?key=f5eef3421c602c6cb7ea224104795888&targetDt=20230109')
.then((req)=>{
const boxOffice = req.data.boxOfficeResult.dailyBoxOfficeList;
setBoxOffice(boxOffice);
console.log(boxOffice);
})
.catch((err)=>{
console.log('통신시 오류가 발생했습니다.')
})
}
// const usePromise = () => {
// return new Promise(resolve,reject) => {
// // var items =
// }
// }
const loadBoxOffice2 = () => {
loadBoxOffice()
.then((item) => {
console.log(boxOffice);
})
.catch((err) => {
console.log('오류발생')
})
}
return(
<div className={"container"}>
<div className={"col-sm-8 mx-auto"}>
<table className={'table table-striped table-hover'}>
<thead>
<tr>
<th>순위</th>
<th>제목</th>
<th>개봉일</th>
<th>당일 관람객</th>
<th>누적 관람객</th>
</tr>
</thead>
<tbody>
{boxOffice.map((item)=>{
return(
<tr key = {item.rnum}>
<td>{item.rank}</td>
<td>{item.movieNm}</td>
<td>{item.openDt}</td>
<td>{item.audiCnt}</td>
<td>{item.audiAcc}</td>
</tr>
)
})}
</tbody>
</table>
<hr/>
<div className={"my-3 d-flex justify-content-end"}>
<button className = {"btn btn-outline-primary" }onClick={loadBoxOffice}>영화 순위 조회</button>
{/*<button className = {"btn btn-outline-primary" }onClick={loadBoxOffice}>영화 순위 조회(async/awit)</button>*/}
{/*<button className = {"btn btn-outline-primary" }onClick={loadBoxOffice}>영화 순위 조회(프로미스)</button>*/}
{/*<button className = {"btn btn-outline-primary" }onClick={loadBoxOffice}>영화 순위 조회(axios)</button>*/}
</div>
</div>
</div>
);
}
export default DailyBoxOffice;
// AsyncAwait.jsx
import React from "react";
import axios, {Axios} from "axios";
// async / await : 비동기 처리를 조금 더 쉽게 하기 위해서 개발됨
// 기본적으로 promise를 사용함
// 사용법 :
// async funciton 함수명(매개변수) {
// const 변수명 = await promise를 사용하는 함수();
// const.log(변수명);
// }
function AsyncAwait(props){
const fetchItems = () => {
return new Promise((resolve, reject) => {
var items = [1,2,3];
resolve(items);
});
}
// 프로미스 사용 시 비동기 처리방법
const logItem1 = () => {
//프로미스를 반환하는 함수를 직접 호출해야한다
fetchItems()
.then((item) => {
console.log(item);
})
.catch((err) => {
console.log(err);
});
}
// async / await 사용 시 비동기 처리방식
const logItem2 = async () => {
const resultItems = await fetchItems();
// 이렇게 해도 된다
// resultItems
// .then(() => {
//
// })
// .catch(()=>{
//
// });
console.log(resultItems);
}
//axios사용
const getData = async () => {
// await 비동기가 끝날 때까지 기다렸다가 실행
const {data} = await axios.get('https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList' +
'.json?key=f5eef3421c602c6cb7ea224104795888&targetDt=20230109');
console.log(data.boxOfficeResult.dailyBoxOfficeList);
}
return(
<div>
{/*둘의 결과값은 동일. */}
<button className={"btn btn-primary"} onClick={logItem1}>프로미스 사용</button>
<button className={"btn btn-success"} onClick={logItem2}>async/await 사용</button>
<button className={"btn btn-info"} onClick={getData}>axios와 함께 사용하기</button>
</div>
)
}
export default AsyncAwait;
axios api
https://axios-http.com/kr/docs/api_intro
요청 메소드 명령어
편의를 위해 지원하는 모든 요청 메소드의 명령어를 제공합니다.
이걸 주로 사용한다.
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.options(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
https://axios-http.com/kr/docs/req_config
AxiosRestServer.jsx
server.port=8080
spring.mvc.hiddenmethod.filter.enabled=true
추가해야 한다
post버튼 눌렀을 때
const sendDataPost = () => {
axios.post("http://localhost:8080/async/data1")
.then((req)=>{
console.log(req); //데이터 넘어오는지 확인
})
.catch((err)=>{
});
}
java505_react_test3 / AxiosRestServer.jsx
//AxiosRestServer.jsx
// spring과 데이터 주고받기
import React from "react";
import axios from "axios";
// 버튼을 매개로 요청 서버(get, post, put, delete)
function AxiosRestServer(props){
const sendDataPostdata1 = () => {
axios.post("http://localhost:8080/async/data1",{id : 'a', pw:'1234'})
.then((req)=>{
console.log("post방식으로 통신성공")
console.log(req); //데이터 넘어오는지 확인
})
.catch((err)=>{
});
}
const sendDataGet = () => {
axios.get('http://localhost:8080/async/sendDataGet')
.then((req)=>{
console.log("get방식으로 통신성공")
console.log(req); //데이터 넘어오는지 확인
})
.catch((err)=>{
console.log('get방식으로 통신오류')
});
}
const sendDataPost = () => {
axios.post("http://localhost:8080/async/sendDataPost",null,
{params : {
id : "id",
pw : "pw"
}}
)
.then((req)=>{
console.log("post방식으로 통신성공")
console.log(req); //데이터 넘어오는지 확인
})
.catch((err)=>{
});
}
const sendDataPut = () => {
axios.put('http://localhost:8080/async/sendDataPut',null,
{params : {idx : 50}}
)
.then((req)=>{
console.log("put방식으로 통신성공")
console.log(req); //데이터 넘어오는지 확인
})
.catch((err)=>{
console.log('put방식으로 통신오류')
});
}
const sendDataDelete = () => {
axios.delete('http://localhost:8080/async/sendDataDelete',{params : {idx : 50}})
.then((req)=>{
console.log("delete방식으로 통신성공")
console.log(req); //데이터 넘어오는지 확인
})
.catch((err)=>{
console.log('delete방식으로 통신오류')
});
}
return(
<div className={"container mt-5 p-5"}>
<h1>Axios를 사용한 비동기 통신</h1>
<div className={"row"}>
<div className={"col-sm-8 mx-auto"}>
<div>
</div>
<div className={"my-3 d-flex justify-content-center"}>
<button className = {"btn btn-primary me-3"} onClick={sendDataGet}>get 방식</button>
<button className={"btn btn-success me-3"} onClick={sendDataPost}>post 방식</button>
<button className={"btn btn-info me-3"} onClick={sendDataPut}>put 방식</button>
<button className={"btn btn-danger"} onClick={sendDataDelete}>delete 방식</button>
</div>
</div>
</div>
</div>
)
}
export default AxiosRestServer;
package com.bitc.reactasyncserver.configuration;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// addMapping() : 지정한 패턴에 맞는 페이지에 대해서 접근 권한 확인
// allowedOrigins(url) : 접근 허용할 외부 url
// 1번째 방법
registry.addMapping("/**") // '/'는 최상위 url => 최상위 url에 접근하는 모든 걸 허용하겠다.
.allowedOrigins("http://localhost:3000","http://localhost:4000");
// registry.addMapping("/login/**")
// .allowedOrigins("http://localhost:3000"); //이 페이지만 허용. 다른 페이지는 불허용
}
}
package com.bitc.reactasyncserver.Controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
// CROS 오류 : Cross Origin Resource Sharing의 줄임말. 동일한 주소 내에서만 리소스를 공유할 수 있다.
// 스프링에서는 CROS 허용을 위해서 @CrossOrigin 어노테이션을 사용하여 처리한다.
// @CrossOrigin : 해당 어노테이션을 사용하면 지정한 도메인에 대해서 접근을 허용한다.
// @CrossOrigin 어노테이션은 메서드, 클래스, configurer 에 설정할 수 있음
// 메서드에 사용 시 지정한 메서드만 접근을 허용한다.
// 클래스에 사용 시 지정한 컨트롤러에 대해서만 접근을 허용한다.
// configurer 에 사용 시 모든 곳에 접근을 허용한다.
// 옵션으로 origins에 접근할 서버의 주소를 입력한다.
@CrossOrigin(origins = {"http://localhost:3000", "http://localhost:4000"}) //2번째 방법
@RequestMapping("/async")
@RestController
public class AsyncServerController {
@RequestMapping("/")
public String index() throws Exception {
return "index";
}
// localhost:3000으로 접근하는 게 있으면 이리로 보내줘라는 뜻
// @CrossOrigin(origins = "http://localhost:3000")
@ResponseBody
@RequestMapping(value = "/data1", method = RequestMethod.POST)
public String asyncDatal() throws Exception {
return "서버와 통신 성공";
}
// get방식 데이터 전송
@RequestMapping(value = "/sendDataGet", method = RequestMethod.GET)
public Object sendDataGet() throws Exception {
Map<String, String> result = new HashMap<>();
result.put("result", "success");
result.put("data", "");
return result;
}
// post방식
@RequestMapping(value = "/sendDataPost", method = RequestMethod.POST)
public Object sendDataPost(@RequestParam("id") String id, @RequestParam("pw") String pw) throws Exception {
Map<String, Object> user = new HashMap<>();
user.put("id", "test1");
user.put("pw", "abcd1234");
Map<String, Object> result = new HashMap<>();
result.put("result", "success");
result.put("data", user);
return result;
}
@RequestMapping(value = "/sendDataPut", method = RequestMethod.PUT)
// requestbody로 해야 데이터 받아진다.
public Object sendDataPut(@RequestParam("idx") int idx) throws Exception {
Map<String, Object> result = new HashMap<>();
result.put("result", "success");
return result;
}
@RequestMapping(value = "/sendDataDelete", method = RequestMethod.DELETE)
public Object sendDataDelete(@RequestParam("idx") int idx) throws Exception {
Map<String, Object> result = new HashMap<>();
result.put("result", "success");
return result;
}
}