掲示板の実装(1)-ページルーティングとAPI設計
13968 ワード
NodeJSサーバの設定
npm init
を使用してpackage.json
ファイルを作成scriptの開始部分を
nodemon server
に置き換えます:これは、nodemonというモジュールを使用してサーバを起動することを意味します.
"scripts": {
" start": "node server/index.js",
"backend": "nodemon server/index.js",
"frontend": "npm run start --prefix client",
"dev": "concurrently \"npm run backend\" \"npm run start --prefix client\""
},
server/index.jsconst express = require("express");
const app = express();
const path = require("path");
const cors = require('cors')
const session = require("express-sesstion")
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const config = require("./config/key");
// const mongoose = require("mongoose");
// mongoose
// .connect(config.mongoURI, { useNewUrlParser: true })
// .then(() => console.log("DB connected"))
// .catch(err => console.error(err));
const mongoose = require("mongoose");
const connect = mongoose.connect(config.mongoURI,
{
useNewUrlParser: true, useUnifiedTopology: true,
useCreateIndex: true, useFindAndModify: false
})
.then(() => console.log('MongoDB Connected...'))
.catch(err => console.log(err));
app.use(cors())
//to not get any deprecation warning or error
//support parsing of application/x-www-form-urlencoded post data
app.use(bodyParser.urlencoded({ extended: true })); //extended: true : 배열같은 추가적인 데이터를 쓸수있도록
//to get json data
// support parsing of application/json type post data
app.use(bodyParser.json()); //데이터를 주고받을때 json 형식 사용
app.use(cookieParser());
app.use(session({
resave: false,
saveUninitialized : true,
secret: "flowersayo",
cookie:{
httpOnly: true, //https
secure: false
}
})
);
app.use('/api/users', require('./routes/users')); // router로 분리
//use this to show the image you have in node js server to client (react js)
//https://stackoverflow.com/questions/48914987/send-image-path-from-node-js-express-server-to-react-client
app.use('/uploads', express.static('uploads'));
// Serve static assets if in production
if (process.env.NODE_ENV === "production") {
// Set static folder
// All the javascript and css files will be read and served from this folder
app.use(express.static("client/build"));
// index.html for all page routes html or routing and naviagtion
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "../client", "build", "index.html"));
});
}
const port = process.env.PORT || 5000
app.listen(port, () => { //서버를 실제적으로 실행하는 부분
console.log(`Server Listening on ${port}`)
});
ネストされたルーティングが必要
苦悩の始まり?
ゲームページを実現するために必要なすべてのページをルーティングすると同時に、突然アプリケーションが作成されます.jsのすべてのページを
ルーティングが有効かどうか考えています.例えば、/forum/free
ページに入ると、フリー掲示板の完全なリストが表示され、/forum/free/{글아이디}
に特定の記事の詳細ページが表示されている場合、どうすればいいですか?/forum/free
でswitch処理をする方法はないかと考えています.もし存在するページが1億個あったら?1つの素子に1億個の素子をすべてルーティングすることは不可能だと思います.検索してみると중첩 라우팅
まで学べます.
https://www.daleseo.com/react-router-nested/
:アプリケーションに必要なすべてのパスとコンポーネント間のマッピングが、上記の最上位コンポーネント上で行われる場合、アプリケーションの規模が大きくなるにつれてメンテナンスが困難になります.しかし、サブコンポーネントレベルごとにより低レベルのルーティングをモジュール化できると、メンテナンスが容易になり、全体的により柔軟なルーティング実装を実現することができる.
これからは、<App>
コンポーネントを介して/forum/free
パスをフリーフォーラムページ全体に接続し、<FreeforumPage>
コンポーネントを使用して最初のルーティングを行い、<FreeforumPage>
で2番目のルーティングを行います.また,同様の作業も攻略掲示板,創意掲示板で繰り返し行われる.
1回目のルーティングを実施する-App.jsに次のコードを追加<Route exact path="/forum" component={Auth(ForumPage, true)} />
<Route exact path="/forum/free" component={Auth(FreeForumPage, true)} />
<Route exact path="/forum/playtip" component={Auth(PlayTipForumPage, true)} />
<Route exact path="/forum/idea" component={Auth(IdeaForumPage, true)} />
ネストされたルーティングを実装するには、まず、ReactRouterの<Route>
コンポーネントのcomponent propにどの値が渡されるかを知る必要がある.React Routerは、match
、location
、history
の3つの支柱を渡します.さらに,オーバーラップルーティングを実現する際に,特にマッチング情報を含むmatchを用いて試みる.match.urlは、<Link>
コンポーネントに使用され、マッチングされる.pathは<Route>
素子に用いられる.match.urlとmatch.pathの違いはmatchです.urlは実際には一致するURL文字列(ex./articles/1)を含み、matchは.pathには、一致するパスのモード(ex./article/:id)が含まれます.
❤ console.ログの結果
2回目のルーティングの実装import React from 'react'
import { Route, Switch } from "react-router-dom";
import PostViewPage from './section/PostViewPage';
import PostCreatePage from './section/PostCreatePage';
function FreeForumPage({match}) {
//match.path가 free/
return (
<div>
<Route exact path={`${match.path}/create`} component={PostCreatePage} />
<Route exact path={`${match.path}/:postId`} component={PostViewPage} />
</div>
)
}
export default FreeForumPage
? exactの存在とexactの存在の違い
ホームコンポーネントをルーティングするときにexcelが設定されている場合、ホームコンポーネントはパスが完全に一致している場合にのみオフセットされます.逆にexceptが設定されていない場合は、/problem/exなどのサブリンクがあっても、問題のある構成部品はオフセットできます.
プリプロセッシング
ページルーティングが完了し、CRUDの実装が開始されます.
<Route exact path="/forum" component={Auth(ForumPage, true)} />
<Route exact path="/forum/free" component={Auth(FreeForumPage, true)} />
<Route exact path="/forum/playtip" component={Auth(PlayTipForumPage, true)} />
<Route exact path="/forum/idea" component={Auth(IdeaForumPage, true)} />
import React from 'react'
import { Route, Switch } from "react-router-dom";
import PostViewPage from './section/PostViewPage';
import PostCreatePage from './section/PostCreatePage';
function FreeForumPage({match}) {
//match.path가 free/
return (
<div>
<Route exact path={`${match.path}/create`} component={PostCreatePage} />
<Route exact path={`${match.path}/:postId`} component={PostViewPage} />
</div>
)
}
export default FreeForumPage
ページルーティングが完了し、CRUDの実装が開始されます.
https://flamingotiger.github.io/style/react-bootstrap/
import 'bootstrap/dist/css/bootstrap.min.css';
https://itprogramming119.tistory.com/entry/React-React%EC%97%90%EC%84%9C-jQuery-%EC%82%AC%EC%9A%A9-%EB%B0%A9%EB%B2%95
import React from 'react'
import {CKEditor} from 'ckeditor4-react';
import {Button,Form} from 'react-bootstrap';
import axios from 'axios';
import $ from 'jquery';
import {} from 'jquery.cookie';
axios.defaults.withCredentials=true;
const headers = {withCredentials: true};
function PostCreatePage({match}) {
console.log(match)
return (
<div style={{color:'white'}}>
<CKEditor></CKEditor>
</div>
)
}
export default PostCreatePage
API設計
/api/board/create
// 게시글 추가하기
router.post('/create',(req,res)=>{
const board = new Board(req.body)
board.save((err,doc)=>{
if(err) return res.status(400).send(err);
else res.status(200).json({success: true,doc:doc})
});
})
/api/board/delete
// 게시글 삭제
router.post('/remove',(request,response)=>{
Board.findOneAndDelete({postId: request.body.postId ,writer : request.body.writer}) // 이 두 조건에 해당하는 db모델 지우기.
.exec((err,doc)=>{
if(err) return response.status(400).send(err);
else response.status(200).json({success: true, doc :doc});
})
})
/api/board/update
//게시글 수정 요청
router.post('/update',(req,res)=>{
Board.update(
{postId: req.body.postId},
{$set:{
writer: req.body.writer,
title : req.body.title,
content : req.body.content
}})
.exec((err,doc)=>{
if(err) return response.status(400).send(err);
else response.status(200).json({success: true, doc :doc});
});
});
/api/board/getBoardDetail
// 특정 게시글 내용 불러오기 요청
router.post('/getBoardDetail',(req,res)=>{
Favorite.find({postId: req.body.postId})
.exec((err,board)=>{
if(err) return response.status(400).send(arr)
return response.status(200).json({success: true, board})
})
});
/api/board/getBoardList
// 전체 게시글 내용 불러오기 요청
router.post('/getBoardList',(req,res)=>{
Favorite.find({sort:{createdAt:-1}})
.exec((err,boards)=>{
if(err) return response.status(400).send(arr)
return response.status(200).json({success: true, boards})
})
});
Reference
この問題について(掲示板の実装(1)-ページルーティングとAPI設計), 我々は、より多くの情報をここで見つけました https://velog.io/@flowersayo/게시판-구현하기-1テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol