dukDukz
React Next | 동적 라우팅 | SSR server side rendering 본문
# 클릭시 해당 글만 가져오는
.../posts/1
해당 id 값만 가져오는
/pages/posts/[id].jsx 생성
이전에는 이렇게 했었지.
import { useRouter } from "next/router"
const Post = ()=>{
const router = useRouter()
const {id} = router.query
return(
<>
hello {id}
</>
)
}
export default Post
이거를 서버사이드렌더링으로 바꿔보자구!
import wrapper from "../../Providers/createCtx"
import { GET_POSTS_DETAIL } from "../../reducers/post"
import { END } from 'redux-saga'
import { useSelector } from "react-redux"
import Link from 'next/link'
const Post = ()=>{
const post = useSelector(state => state.post.postDetaill)
return(
<>
{/* hello {id} */}
<h3>{post.title}</h3>
<dl>
<dt>{post.id}</dt>
<dt>{post.body}</dt>
</dl>
<Link href="/posts/"><a>목록가기</a></Link>
</>
)
}
export const getServerSideProps = wrapper.getServerSideProps((Store)=> async (req,res)=>{
const {id} = req.params
// console.log(id);
Store.dispatch(GET_POSTS_DETAIL(id))
Store.dispatch(END)
await Store.sagaTask.toPromise()
})
export default Post
여기서 중요한 부분은
import wrapper from '../Providers/createCtx'
import { END } from 'redux-saga'
export const getServerSideProps = wrapper.getServerSideProps((Store)=> async (req,res)=>{
const {id} = req.params
Store.dispatch(GET_POSTS_DETAIL(id))
Store.dispatch(END)
await Store.sagaTask.toPromise()
})
받아들이자고!
익명함수 안에 익명함수 넣는 늬낌
localhost:3000/posts/[id]
req.params 에서 id 값을 가져와서
dispatch 보내야 하는데 Store 안에 dispatch 가 있다고 한다. 저기 인자값은 보통 state 혹은 Store 로 쓴다고 함
어쨌든 보내고 disptach(END) 도 해줘야함.
[reducers/post.js]
export const initalState = {
posts: [],
postDetaill: null,
loadding: false,
}
/* REDUX ACTIONS */
export const GET_POSTS_REQUEST = "GET_POSTS_REQUEST"
export const GET_POSTS_SUCCESS = "GET_POSTS_SUCCESS"
export const GET_POSTS_FAIL = "GET_POSTS_FAIL"
export const GET_POSTS_DETAIL_REQUEST = "GET_POSTS_DETAIL_REQUEST"
export const GET_POSTS_DETAIL_SUCCESS = "GET_POSTS_DETAIL_SUCCESS"
export const GET_POSTS_DETAIL_FAIL = "GET_POSTS_DETAIL_FAIL"
export const GET_POST = () => {
return {
type: GET_POSTS_REQUEST
}
}
export const GET_POSTS_DETAIL = (data) => {
return {
type: GET_POSTS_DETAIL_REQUEST,
data
}
}
const reducer = (state = initalState, action) => {
switch (action.type) {
case GET_POSTS_REQUEST:
return {
...state,
loadding: true
}
case GET_POSTS_SUCCESS:
//console.log("도착했니? -- ",action);
return {
...state,
posts: [...state.posts, ...action.data],
loadding: false,
}
case GET_POSTS_FAIL:
return {
...state,
loadding: false,
}
case GET_POSTS_DETAIL_REQUEST:
return {
...state,
loadding: true
}
case GET_POSTS_DETAIL_SUCCESS:
console.log("detail === ",action);
return {
...state,
loadding: false,
postDetaill : action.data
}
case GET_POSTS_DETAIL_FAIL:
return {
...state,
loadding: false
}
default:
return state
}
}
export default reducer
이 id 값에 해당하는 값을 initalState의 postDetail 에 담을것이다.
이게 더 정확함 post 에서 필터링하는것보다는
export const GET_POSTS_DETAIL_REQUEST = "GET_POSTS_DETAIL_REQUEST"
export const GET_POSTS_DETAIL_SUCCESS = "GET_POSTS_DETAIL_SUCCESS"
export const GET_POSTS_DETAIL_FAIL = "GET_POSTS_DETAIL_FAIL"
export const GET_POSTS_DETAIL = (data) =>{
return{
type : GET_POSTS_DETAIL_REQUEST,
data
}
}
case 도 3개
추가함
case GET_POSTS_DETAIL_SUCCESS:
console.log("detail === ",action);
return {
...state,
loadding: false,
postDetail : action.data
}
여기서 state 값에 postDetail 안에 그 해당 id 값에 맞는 data를 담았음
[saga/postSaga.js]
import {all,fork,takeLatest,call,put, take} from 'redux-saga/effects'
import axios from 'axios'
import {
GET_POSTS_REQUEST,
GET_POSTS_SUCCESS,
GET_POSTS_FAIL,
GET_POSTS_DETAIL_REQUEST,
GET_POSTS_DETAIL_SUCCESS,
GET_POSTS_DETAIL_FAIL
} from '../reducers/post'
let BaseURL = process.env.NODE_ENV.backurl || 'https://jsonplaceholder.typicode.com'
async function getPostAPI(data = "") {
const response = await axios.get(`${BaseURL}/posts/${data}`)
return response
}
/* 전체 post 가져옴 */
function* getPosts(){
// API 통신 web server랑 통신을 하게될겁니다. fetch axios
try{
const {data} = yield call(getPostAPI)
//console.log(data);
yield put({
type:GET_POSTS_SUCCESS,
data
})
} catch (e) {
yield put({
type:GET_POSTS_FAIL,
data:'ERROR'
})
}
}
function* watchPosts(){
yield takeLatest(GET_POSTS_REQUEST,getPosts)
}
/* 디테일 */
function* getPostDetail (action) {
try {
const {data} = yield call(getPostAPI,action.data)
yield put({
type : GET_POSTS_DETAIL_SUCCESS,
data
})
} catch (e) {
yield put({
type:GET_POSTS_DETAIL_FAIL,
data:'ERROR'
})
}
}
function* watchPostDetail(){
yield takeLatest(GET_POSTS_DETAIL_REQUEST,getPostDetail)
}
export default function* postSaga(){
yield all([
fork(watchPosts),
fork(watchPostDetail)
])
}
/saga/postSaga.js
GET_POSTS_DETAIL_REQUEST,
GET_POSTS_DETAIL_SUCCESS,
GET_POSTS_DETAIL_FAIL
얘네를 import 해옴
[/pages/posts/[id].jsx]
import wrapper from "../../Providers/createCtx"
import { GET_POSTS_DETAIL } from "../../reducers/post"
import { END } from 'redux-saga'
import { useSelector } from "react-redux"
import Link from 'next/link'
const Post = ()=>{
const post = useSelector(state => state.post.postDetail)
return(
<>
{/* hello {id} */}
<h3>{post.title}</h3>
<dl>
<dt>{post.id}</dt>
<dt>{post.body}</dt>
</dl>
<Link href="/posts/"><a>목록가기</a></Link>
</>
)
}
export const getServerSideProps = wrapper.getServerSideProps((Store)=> async (req,res)=>{
const {id} = req.params
// console.log(id);
Store.dispatch(GET_POSTS_DETAIL(id))
Store.dispatch(END)
await Store.sagaTask.toPromise()
})
export default Post
const post = useSelector(state => state.post.postDetail)
이걸로 찾아오고 뿌려주면 됨
'웹 개발 > React' 카테고리의 다른 글
React 복습, 자주쓰는 React Hooks (0) | 2022.01.21 |
---|---|
React 에서 사용하기 좋은 아이콘 (0) | 2021.12.11 |
React Next | 인피니티 스크롤 (Infinite Scroll) (0) | 2021.08.27 |
React Next 기본 틀 (0) | 2021.08.27 |
0806 Redux-saga (0) | 2021.08.06 |