리액트 _1_만개의레시피 리액트버전
*HOOKS
- state(데이터)관리 ==>useState()
- 화면 출력 전에 데이터 읽기 => useEffect(()=>{},[])
=> 비동기화 ===> redux-thunk
redux-saga
- useCallback: function을 기억함 => 싱글턴
- React.memo ==> useMemo()
*전역변수: useContext(),
리덕스: useDispatch(이벤트를 통해 데이터 받기), useSelector(이벤트 컨트롤러), useReducer(디스패치로 받은 값 넘겨주기)
1. 새프로젝트를 만든다.
2. package.json에다가 구성을 해준다.
"axios": "^0.19.2", --파일 받을 때 사용하는 것 "express": "^4.17.1", "mongodb": "^3.5.8", "path": "^0.12.7", "request": "^2.88.2", "xml2js": "^0.4.23", --xml을 json으로 변경하는 것 "react-router": "^5.2.0", --라우터 할 때 사용하는 것 "react-router-dom": "^5.2.0"--라우터 할 때 사용하는 것 |
3. 디렉토리를 하나 생성한다 (이름:components)
안에 js파일을 생성한다.
*부가적으로 header(메뉴역할)을 추가해준다.
4. header(메뉴역할)를 먼저 만든다.
css 디자인과 구성은 아래 링크에서 가져온다. 반드시 링크도 받아올 것.
https://www.w3schools.com/bootstrap/bootstrap_navbar.asp
링크연결을 위해 NavLink를 import 한다. {}은 뒤에있는 라이브러리에서 여러개를 가져올 때 사용한다.
<a>태그를 NavLink로 바꿔준다. href는 to로 바꿔서 링크연결을 해준다.
import React from "react";
import {NavLink} from "react-router-dom";
//render()
export default function Header() {
/*
* to={"/"} : http://localhost:3000/ 이걸로 접속한다는 의미
*
* */
return(
<nav className="navbar navbar-inverse">
<div className="container-fluid">
<div className="navbar-header">
<NavLink className="navbar-brand" to={"/"}>STST 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>
)
}
to 앞에 exact를 붙이면 default로 설정이 된다.
5. App.js에서 시작하기 때문에 여기서 만든 js 파일을 모아둔다.
BrowserRouter,Route,Switch를 import 한다.
import {BrowserRouter as Router, Route,Switch} from "react-router-dom";
사용자가 사이트 주소를 주면 route가 받고 선택한 내용을 Switch가 받고 그 선택을 하는 애는 BrowserRouter다.
import React from 'react';
import {BrowserRouter as Router, Route,Switch} from "react-router-dom";
import Header from "./components/Header";
import Recipe from "./components/Recipe";
import RecipeDetail from "./components/RecipeDetail";
import Chef from "./components/Chef";
import ChefDetail from "./components/ChefDetail";
import RecipeFind from "./components/RecipeFind";
import RecipeNews from "./components/RecipeNews";
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;
결과) 메뉴를 누르면 페이지 글이 달라진다.
6. spring으로 출력하면 좋겠지만 상황이 안되므로 recipe-server를 만들어서 화면에 출력해주려고 한다.
bind() => IP와 PORT 연결해주는 역할 listen() => 대기상태 accept() => 클라이언트가 접속을 했을 때 처리하는 부분 |
const express=require("express")
//라이브러리 로드
//서버 생성
const app=express();
//서버를 구동
/*
bind() => IP와 PORT 연결해주는 역할
listen() => 대기상태
accept() => 클라이언트가 접속을 했을 때 처리하는 부분
*/
app.listen(3355,()=>{
console.log("Server Start...","http://localhost:3355")
})
app.all('/*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
//클라이언트와 통신하는 부분
//사용자(클라이언트)의 URI를 받아옴 => 사용자가 이용할 수 있는게 브라우저밖에 없어서 이걸 가져오는 것.URI 주소는 다 다르기 때문에 이걸로 구분
//mongoDB 연결
const Client = require("mongodb").MongoClient;
//mongoDB connection
app.get('/recipe_',(request,response)=>{
//request = 사용자가 보내준 요청 정보
//요청 처리
//response = 결과를 전송
var page=request.query.page; //request.getParameter("page")
var rowSize = 12;
var skip=(page*rowSize)-rowSize;
var url="mongodb://211.238.142.181:27017"; //몽고디비 주소
Client.connect(url, (err,client)=>{
var db = client.db('mydb');
//db.collection('recipe').find({}) == select * from recipe
//find({"title":{"$regex":".*"+값}} == select * from recipe where title Like '%값%'
db.collection('recipe').find({}).skip(skip).limit(rowSize).toArray((err,docs)=>{ //데이터가 배열이 아닌 낱개로 들어가서 이렇게 해줌
//요청한 사용자에게 값 보내기
response.json(docs);
client.close();
})
});
})
7. >node recipe-server 를 터미널에 쳐서 서버를 돌린다.
http://localhost:3355/recipe?page=1 를 들어가면 12개씩 출력된다.
8. Recipe.js를 작성한다.
import React, {useState,useEffect} from "react";
import axios from 'axios';
export default function Recipe() {
const [recipe,setRecipe]=useState([]); //배열로 받아야 하기 때문에 이렇게 작성
const [page,setPage]=useState(1);
useEffect(()=>{
//서버를 연결해서 데이터를 읽어온 후 setRecipe에 저장
axios.get('http://localhost:3355/recipe',{
params:{
page:page //http:localhost:3355/recipe?page=1 과 동일한 형태
}}).then((result)=>{ //배열 값이 result에 저장된 상태
setRecipe(result.data);
})
},[]) //deps를 주어야 한번만 된다.
const html = recipe.map((m)=>
<div className="col-md-4">
<div className="thumbnail">
<img src={m.poster} alt="Lights" style={{"width":"100%"}}/>
<div className="caption">
<p style={{"fontSize":"9pt"}}>{m.title}</p>
<sub style={{"color":"gray"}}>{m.chef}</sub>
</div>
</div>
</div>)
//출력할 데이터 모아서 return에 전송
return(
<div className={"row"}>
{html}
</div>
)
}
결과) 터미널 하나를 더 열어서 실행시키면 이렇게 화면이 뜬다.