dukDukz

React Next | 동적 라우팅 | SSR server side rendering 본문

웹 개발/React

React Next | 동적 라우팅 | SSR server side rendering

헤일리_HJ 2021. 8. 27. 16:48

# 클릭시 해당 글만 가져오는

.../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