next 와 redux-saga 사용

Felix Yi·2020년 3월 20일
0

getInitialProps 를 사용하므로, SSR 정적 최적화는 없다. 그리고, 서버사이드에서 리덕스를 사용해야할 이유가 왜 있는지 자꾸 생각을 해보게 된다. 크로스 플랫폼 환경에서 새로고침 시 정보를 저장하기 위해서, 것도 인증정보 때문이라면 때문이라면 redux-persist 를 써도 될텐데. 왜 구지 express-session 을 쓸까? 알아갈 수록 궁금증이 늘어가네.

next-redux-saga

https://github.com/bmealhouse/next-redux-saga

next-redux-wrapper 에 의해 생긴 리덕스 스토어를 사용한다고 함.

스토어 생성

preloadedState: The initial state. You may optionally specify it to hydrate the state from the server in universal apps, or to restore a previously serialized user session. If you produced reducer with combineReducers, this must be a plain object with the same shape as the keys passed to it. Otherwise, you are free to pass anything that your reducer can understand.
https://redux.js.org/api/createstore#createstorereducer-preloadedstate-enhancer

import {createStore, applyMiddleware} from 'redux'
import createSagaMiddleware from 'redux-saga'
import rootReducer from './root-reducer'
import rootSaga from './root-saga'

function configureStore(preloadedState, {isServer, req = null}) {

  /**
   * Recreate the stdChannel (saga middleware) with every context.
   */

  const sagaMiddleware = createSagaMiddleware()

  /**
   * Since Next.js does server-side rendering, you are REQUIRED to pass
   * `preloadedState` when creating the store.
   */

  const store = createStore(
    rootReducer,
    preloadedState,
    applyMiddleware(sagaMiddleware)
  )

  /**
   * next-redux-saga 는 `getInitialProps` 처리 중에 스토어에 붙기 위해 `sagaTask` 에 의존함.
   * 이건, 클라이언트에 결과를 보내기 전에 rootSaga 를 await 하는데 사용됨.
   * However, next-redux-wrapper creates two server-side stores per request:
   * One before `getInitialProps` and one before SSR (see issue #62 for details).
   * 서버사이드에서, 우리는 `getInitialProps` 중에서만 rootSaga 를 실행함: 
   */

  // isServer 는 SSR 빌드 타임을 이야기 하는 거 같음.
  // 즉 빌드 타임이 아니라 Request Time 이면 사가태스크 실행해서 store 에 넣으라고 하는 듯.
  if (req || !isServer) {
    store.sagaTask = sagaMiddleware.run(rootSaga)
  }

  return store
}

export default configureStore

Configure Custom _app.js Component

next.js 기본 App 작동을 커스텀화하자. 즉 모든 페이지(컴포넌트)를 받아서 Provier 로 감싸고, 무조건 위에서 만든 store 의 state 를 제공하도록 함.

import React from 'react'
import {Provider} from 'react-redux'
import App, {Container} from 'next/app'
import withRedux from 'next-redux-wrapper'
import withReduxSaga from 'next-redux-saga'
import configureStore from './configure-store'

function MyApp({Component, pageProps, store}) {
  return (
      <Container>
        <Provider store={store}>
          <Component {...pageProps} />
        </Provider>
      </Container>
    )
}

MyApp.getInitialProps = async ({Component, ctx}) => {
    let pageProps = {}

    // SSR 때 data population 하면
    if (Component.getInitialProps) {
      // ctx (store 가 들어있음) 를 주입
      pageProps = await Component.getInitialProps(ctx)
    }

    return {pageProps}
}

export default withRedux(configureStore)(withReduxSaga(ExampleApp))

Connect Page Components

요건 그냥 ContextAPI 임.

import React, {Component} from 'react'
import {connect} from 'react-redux'

class ExamplePage extends Component {
  // _app.js getInitialProps 훅에서 주입된 ctx 에서 store 추출 후
  static async getInitialProps({store}) {
    // 필요한 비동기 요청 실행
    store.dispatch({type: 'SOME_ASYNC_ACTION_REQUEST'})
    return {staticData: 'Hello world!'}
  }

  render() {
    return <div>{this.props.staticData}</div>
  }
}

export default connect(state => state)(ExamplePage)
profile
다른 누구와도 같은 시장 육체 노동자

0개의 댓글