WEB/react

react - next 프레임워크를 활용해 ssr(server side rendering) 간단히 해결

Woogamza 2019. 8. 20. 03:06
728x90

server side rendering을 next의 getInitialProps를 활용해 간단하게 해결해보자.

redux와 redux-saga를 활용해 문제를 해결한다.

다양한 액션 중 블로그에서 포스팅한 글들을 프론트 서버에서 백엔드 서버로 요청하는 것을 해보자.

pages 폴더의 _app.js 에서 useEffect를 활용해 dispatch를 한다고 하면

1. next와 redux-saga를 연결할 패키지를 다운 받는다

npm i next-redux-saga
npm i next-redux-wrapper
npm i redux-saga

2. saga를 config 하자.

(_app.js) 파일
import rootSaga from './saga.js' // saga를 지정해 놓은 파일
import withRedux from 'next-redux-wrapper' //next와 redux의 미들웨어( 여기서는 saga)를 연결
import withReduxSaga from 'next-redux-saga'
import createSagaMiddleware from 'redux-saga'
///대충
///redux관련

const App = ({Component, store, pageProps}) =>{
    //대충 redux 관련 코드, 모든 페이지에 적용할 코드 들 (ex Provider로 store 건내주기)
}

//...
//대충 propTypes 관련 코드
//...

App.getInitialProps = async (context) => {
    let pageProps = {}
    const {ctx, Component} = context //ctx는 프론트 서버가 실행하면서 next가 context를 전달해줌.
    const state = ctx.store.getState() // redux의 store에서 state를 getState를 통해 꺼내온다
    ctx.store.dispatch({
        type: LOAD_POST_REQUEST //포스팅한 글들을 reducer를 이용한 dispatch
    })
    pageProps = await Component.getInitialProps(ctx)
    return pageProps
}

const storeConfig = (initialState, options) =>{
    const sagaMiddleware = createSagaMiddleWare()
    const middlewares = [sagaMiddleware] //middleware들 다 여기로 모여라~
    const enhancer = process.env.NODE_ENV === 'production'
    ? compose(applyMiddleware(...middlewares))
    : compose(
      applyMiddleware(...middlewares),
      !options.isServer && typeof window.__REDUX_DEVTOOLS_EXTENSION__ !== 'undefined' ? window.__REDUX_DEVTOOLS_EXTENSION__() : f => f,
    ) // chrome redux devtools 에 대한 설정. (redux devtools를 개발모드에서만 사용하고 싶어요 라는 내용)
  const store = createStore(reducer, initialState, enhancer);
  store.sagaTask = sagaMiddleware.run(rootSaga);
  return store;
}


export default withRedux(storeConfig)(withReduxSaga(App))

그런데, withcredential 옵션을 사용할때 쿠키를 넣어주어야 한다면은

App.getInitialProps = async (context) => {
    let pageProps = {}
    const {ctx, Component} = context //ctx는 프론트 서버가 실행하면서 next가 context를 전달해줌.
    const state = ctx.store.getState() // redux의 store에서 state를 getState를 통해 꺼내온다
    const cookie = ctx.isServer ? ctx.req.headers.cookie : '' // 서버에서 요청할때 ctx에 req객체가 붙는다.
    if(ctx.isServer &&cookie){
        axios.defaults.headers.cookie = cookie
    }
    ctx.store.dispatch({
        type: LOAD_POST_REQUEST //포스팅한 글들을 reducer를 이용한 dispatch
    })
    pageProps = await Component.getInitialProps(ctx)
    return pageProps
}

+추가

storeConfig 에서 getInitialProps의 action을 로깅해주는 커스텀 미들웨어를 만들어보자

const storeConfig = (initialState, options) =>{
    const sagaMiddleware = createSagaMiddleWare()
    const middlewares = [sagaMiddleware, (store)=>(next)=>(action)=>{
        console.log(store)
        next(action)
    }] // 커스텀 미들웨어
    const enhancer = process.env.NODE_ENV === 'production'
    ? compose(applyMiddleware(...middlewares))
    : compose(
      applyMiddleware(...middlewares),
      !options.isServer && typeof window.__REDUX_DEVTOOLS_EXTENSION__ !== 'undefined' ? window.__REDUX_DEVTOOLS_EXTENSION__() : f => f,
    ) // chrome redux devtools 에 대한 설정. (redux devtools를 개발모드에서만 사용하고 싶어요 라는 내용)
  const store = createStore(reducer, initialState, enhancer);
  store.sagaTask = sagaMiddleware.run(rootSaga);
  return store;
}