question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Why does saga not execute on the server side, but saga runs normally on the client side?

See original GitHub issue

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),
    // ...
]

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:9 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
iiDestinycommented, Jul 14, 2021

It doesn’t seem to be working, here’s an example of when first launching it using the page for access. It does not execute the asynchronous function inside saga

https://codesandbox.io/s/jovial-night-mtkbt?file=/pages/index.js

image

Because the console.log of the asynchronous function is not printed

image

1reaction
iiDestinycommented, Jul 13, 2021

I hope you can help me to answer my questions, thank you very much!

@kirill-konshin

Read more comments on GitHub >

github_iconTop Results From Across the Web

Why does saga not execute on the server side, but ... - GitHub
Describe the bug Why does saga not execute on the server side, but saga runs normally on the client side? The strange thing...
Read more >
React redux-saga on server side doesn't take action after ...
I have some problems with my universal react app runing with saga. I'm rendering react on server. One of my react component executes...
Read more >
Server Rendering - Redux - JS.ORG
Because the client side executes ongoing code, it can start with an empty initial state and obtain any necessary state on demand and...
Read more >
Pattern: Saga - Microservice Architecture
A client that initiates the saga, which an asynchronous flow, using a synchronous request (e.g. HTTP POST /orders ) needs to be able...
Read more >
How I spent my Christmas enabling SSR | by Craig Taub
The idea is that the user should have a first-class experience anywhere, and that includes on a mobile device or a bad internet...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found