Why does saga not execute on the server side, but saga runs normally on the client side?
iiDestiny opened this issue · comments
Luo Yan commented
Describe the bug
Why does saga not execute on the server side, but saga runs normally on the client side?
The strange thing is that in my local development environment, when I run npm run dev
for the first time, the saga does not work, but when I modify the jsx file and hot load it, the server-side saga works
But when I package it in the production environment, the server-side saga doesn't work
_app.jsx
import { enquireScreen } from 'enquire-js'
import App from 'next/app'
import { withRouter } from 'next/router'
import React from 'react'
import { setRem } from 'lib/rem'
import './style.scss'
import 'css/index.less'
import { DefaultSeo } from 'next-seo'
import SEO from '../../next-seo.config'
import '@/utils/router-event'
import { appWithTranslation } from 'lib/i18n'
import { authCheck } from '@/lib/auth'
import { initNextServer } from '@/lib/next-server'
import { notification } from 'antd'
import { isClient } from '@/utils/helper'
import { userKey, tokenKey } from '@/lib/token'
import { directLogout } from '@/lib/auth'
import wrapper from '../redux/store'
import { END } from 'redux-saga'
import { authLogoutSuccess } from '@/redux/modules/auth/actions'
import {
authLoginSuccess,
authUserInfoSuccess,
authUserInfoRequest,
} from '@/redux/modules/auth/actions'
// @withReduxStore
class NextApp extends App {
constructor(props) {
super(props)
this.state = {
userAgent: {
userAgent: 'pc',
},
isMobile: false,
}
}
static getInitialProps = wrapper.getInitialAppProps(
(store) => async ({ Component, ctx }) => {
let pageProps = {}
store.dispatch(authUserInfoRequest()) // <------------
if (Component.getInitialProps) {
try {
pageProps = await Component.getInitialProps({
...ctx,
store,
})
} catch (e) {
const statusCode = e?.response?.status
if (!isClient() && statusCode === 401) {
store.dispatch(authLogoutSuccess())
ctx.res.clearCookie(userKey)
ctx.res.clearCookie(tokenKey)
ctx.res.writeHead(301, { Location: '/' })
ctx.res.end()
}
}
}
if (ctx.req) {
console.log('Saga is executing on server, we will wait')
store.dispatch(END)
await store.sagaTask.toPromise()
console.log('Saga is executing on server, done')
}
return { pageProps }
}
)
render() {
const { Component, pageProps } = this.props
return (
<>
<DefaultSeo {...SEO} />
<Component {...pageProps} />
</>
)
}
}
export default appWithTranslation(withRouter(wrapper.withRedux(NextApp)))
store.js
import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
import { createWrapper, HYDRATE } from 'next-redux-wrapper'
import rootReducer from './reducers'
import rootSaga from './sagas'
const bindMiddleware = (middleware) => {
if (process.env.NODE_ENV !== 'production') {
const { composeWithDevTools } = require('redux-devtools-extension')
return composeWithDevTools(applyMiddleware(...middleware))
}
return applyMiddleware(...middleware)
}
export const makeStore = () => {
const sagaMiddleware = createSagaMiddleware()
const store = createStore(rootReducer, bindMiddleware([sagaMiddleware]))
store.sagaTask = sagaMiddleware.run(rootSaga)
// Hot reload reducers (requires Webpack or Browserify HMR to be enabled)
if (process.env.NODE_ENV !== 'production' && module.hot) {
module.hot.accept('./reducers', () =>
// eslint-disable-next-line global-require
store.replaceReducer(require('./reducers').default)
)
}
return store
}
export default createWrapper(makeStore, { debug: false })
saga.js
import {
all,
fork,
put,
takeLatest,
takeEvery,
call,
take,
} from 'redux-saga/effects'
import AuthProvider from '@/api/auth'
import { setToken, removeToken, removeUserInfo, setUserInfo } from '@/lib/token'
import {
authLoginSuccess,
actionTypes,
authUserInfoSuccess,
authLogoutSuccess,
authUserInfoRequest,
} from './actions'
function* authLogin({ payload }) {
const { email, password } = payload
try {
const { data } = yield call(AuthProvider.login, {
email: email.trim(),
password,
})
if (data.access_token) {
setToken(data.access_token)
yield put(authLoginSuccess(data.access_token))
yield put(authUserInfoRequest())
}
} catch (e) {
console.log('saga authLogin', e)
yield put(authLoginSuccess(null))
removeToken()
}
}
function* getUserInfo() {
while (true) {
yield take(actionTypes.AUTH_GET_USER_INFO_REQUEST)
try {
const userInfo = yield call(AuthProvider.getUserInfo, {
include: [],
})
console.log('saga getUserInfo', userInfo)
yield put(authUserInfoSuccess(userInfo))
} catch (e) {
yield put(authUserInfoSuccess({}))
removeUserInfo()
}
}
}
function* logout({ payload }) {
try {
yield call(AuthProvider.logout)
removeToken()
removeUserInfo()
yield put(authLogoutSuccess())
} catch (e) {}
}
export default [
takeLatest(actionTypes.AUTH_LOGIN_REQUEST, authLogin),
fork(getUserInfo),
takeLatest(actionTypes.AUTH_LOGOUT_REQUEST, logout),
// ...
]
Luo Yan commented
Resolved