React Router
란, SPA(Single Page Application: 모든코드를 하나의 파일에서 관리) 의 라우팅 문제를 보완할 수 있도록 코드의 모듈화를 가능하게 해주는 라이브러리 입니다.
서로 다른 주소를 가진 view 를 만들어 관리합니다. 즉, component 마다 다른 url 을 호출하여 화면을 부르 있도록 합니다.
function 방식인Hooks
를 적용했습니다.
예제에 대한 클래스 트리입니다.
public
ㄴindex.html
src
ㄴ components
ㄴ Header.js
ㄴ Recipe.js
ㄴ RecipeDetail.js
ㄴ RecipeFind.js
ㄴ RecipeNews.js
ㄴ Chef.js
ㄴ ChefDetail.js
ㄴ App.js
ㄴ index.js
ㄴ server.js
ㄴ package.json
import React from 'react';
import {BrowserRouter as Router, Route, Switch} from "react-router-dom";
import logo from './logo.svg';
import './App.css';
import Header from "./components/Header";
import Recipe from "./components/Recipe";
import RecipeDetail from "./components/RecipeDetail";
import RecipeFind from "./components/RecipeFind";
import RecipeNews from "./components/RecipeNews";
import Chef from "./components/Chef";
import ChefDetail from "./components/ChefDetail";
/*
index.js
ReactDom.render(<App/>, document.getElementById('root'))
<App/> => html 을 읽어서 => <div id="root"></div>
*/
function App() {
return (
<Router>
<Header/>
<div className={"container-fluid"}>
<div className={"jumbotron"}>
<Switch>
<Route exact path={"/"} component={Recipe}/>
<Route path={"/recipe_detail"} component={RecipeDetail}/>
<Route path={"/chef"} component={Chef}/>
<Route path={"/chef_detail"} component={ChefDetail}/>
<Route path={"/news"} component={RecipeNews}/>
<Route path={"/find"} component={RecipeFind}/>
</Switch>
</div>
</div>
</Router>
);
}
export default App;
import React from "react";
import {NavLink} from "react-router-dom";
// <NavLink exact to={""}>
// NavLink 에서 exact 는 default 값이다.
//render()
export default function Header() {
return (
<nav className="navbar navbar-inverse">
<div className="container-fluid">
<div className="navbar-header">
<NavLink className="navbar-brand" to={"/"}>SIST Recipe</NavLink>
</div>
<ul className="nav navbar-nav">
<li className="active"><NavLink exact to={"/"}>레시피</NavLink></li>
<li><NavLink to={"/chef"}>쉐프</NavLink></li>
<li><NavLink to={"/news"}>레시피뉴스</NavLink></li>
<li><NavLink to={"/find"}>레시피검색</NavLink></li>
</ul>
</div>
</nav>
)
}
RecipeDetail.js
RecipeFind.js
... 각 화면은 아래와 같이 Recipe.js
와 같은 함수 구조로 되어있다.import React from "react";
export default function Recipe() {
return (
<div><h1>레시피</h1></div>
)
}
MongoDB 서버를 구축한다.
skip => offset 과 비슷하다.
- 라이브러리 로드
- 서버생성
- 서버구동
- cross domain 허용
- 클라이언트 통신 및 몽고디비 연결
- request 요청처리 => reponse 결과전송
const express=require("express")
const app = express();
/*
* bind() => IP, PORT 를 연결 => 개통
* listen() => 대기상태
* accept() => 클라이언트가 접속시에 처리
* */
app.listen(3355, ()=>{
console.log("Server Start ...", "http://localhost:3355")
})
// cross domain
app.all('/*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
// 클라이언트 통신
// 사용자 URI => /recipe?page=1
// 몽고디비 연결
// MongoDB Connection
const Client = require("mongodb").MongoClient;
app.get('/recipe', (request, response)=>{
// request => 사용자가 보낸 요청 : page, id, pwd
// 요청 처리
// response => 결과전송
var page= request.query.page; //request.getParameter("page")
var rowSize =12;
var skip = (page*rowSize) - rowSize;
// 1page => skip=0
// 2page => skip 12(버림) ==> 13
var url = "mongodb://211.238.142.181:27017";
Client.connect(url, (err, client)=>{
var db = client.db('mydb');
// SELECT * FROM recipe => find{()}
// SELECT * FROM recipe WHERE no=1 => find{(no:1)}
// skip => offset 과 비슷함.
// toArray(err, docs) 콜백 함수: 가져온 데이터를 배열로 묶어줌. (docs에 있음)
db.collection('recipe').find({}).skip(skip).limit(rowSize)
.toArray((err, docs)=>{
response.json(docs);
client.close();
});
})
})
axios.get({URL
, params:{}
}).then((result
)=>{ setState변수(result.data)
})
recipe
데이터에 넣어준 값을 화면에 그려준다.Recipe.js 내의 음식 이미지를 클릭하면 그 이미지에 해당하는 상세보기로 넘어갈 수 있도록 NavLink 를 달아줄 것이다.
_
RecipeDetail
의 path를 다음과 같이 바꿔준다. (no 변수가 추가됨)/recipe_detail
→ /recipe_detail/:no
<Route path={"/recipe_detail/:no"} component={RecipeDetail}/>
/recipe_detail/"+m.no
<NavLink to={"/recipe_detail/"+m.no}>
<img src={m.poster} alt="Lights" style={{"width":"100%"}}/>
</NavLink>
match
를 사용하여 넘길 수 있다.props.match.params.no
방법1)
export default function RecipeDetail(props) {
return (
<div><h1>레시피 상세보기: {props.match.params.no}</h1></div>
)
}
방법2) match
클래스를 props에 할당.
export default function RecipeDetail(props) {
const {match} = props;
return (
<div><h1>레시피 상세보기: {match.params.no}</h1></div>
)
}
no
라는 파라미터는 서버단에서 request.query.no
로 받을 수 있다./recipe-detail?no=1
의 형식이다.http://localhost:3355/recipe-detail
를 사용할 수 있다.app.get('/recipe-detail', (request, response)=>{
// 파라미터를 받는 방법
var no = request.query.no;
Client.connect(URL, (err, client)=>{
var db = client.db('mydb');
// 형변환 : Number() or parseInt()
db.collection('recipe_detail').find({no:Number(no)}).toArray((err, docs)=>{
response.json(docs[0]); // Array 타입이기 때문에 하나의 Object 만 가져온다.
client.close();
})
});
})
const [detail, setDetail] = useState({});
useEffect(()=>{
axios.get('http://localhost:3355/recipe-detail', {
params:{
no: match.params.no
}
}).then((result)=>{
setDetail(result.data);
})
},[])