Next.js: Async redux thunk in SERVER breaks

Created on 5 Jun 2019  路  12Comments  路  Source: vercel/next.js

Examples bug report

Example name

with-redux-thunk

Describe the bug

Async thunk does not work in SSR

To Reproduce

The example repo: with-redux-thunk

In the above example, serverRenderClock is synchronous
```synchronous dispatch
export const serverRenderClock = isServer => dispatch => {
return dispatch({ type: actionTypes.TICK, light: !isServer, ts: Date.now() })
}

everything work expected, on SSR, the example will render the time on the server

However, if we try to make serverRenderClock async, it breaks
using below async serverRenderClock
```async dispatch
export const serverRenderClock= usServer = dispatch => {
  return setInterval(() => {
    dispatch({ type: actionTypes.TICK, light: !isServer, ts: Date.now() })
  }, 1000)
}

The new getInitialProps

static async getInitialProps ({ reduxStore, req }) {
    const isServer = !!req
    await reduxStore.dispatch(serverRenderClock(isServer))
    return {}
  }

Expected behavior

With the new async dispatch, it should also render the server time as synchronous

Additional context

Above is an generalized example. However, let's say if we want to dispatch an async thunk with API call in server, the scenario is similar
For example, making async api call in thunk in the server side

getResultFromApi = () => async dispatch => {
   const response = await fetch('http://www.test-api.com')
   const data = await response.json()
   dispatch(setSuccessResponseAction(data)
}

How can I use above async thunk in my getInitialProps so SSR works properly?

good first issue

Most helpful comment

@MarchWorks yes, you're right. I've found that getInitialProps in index.js is not async https://github.com/zeit/next.js/blob/0dbd3b98eca0bee01a05b8414a60c48abba76abd/examples/with-redux-thunk/pages/index.js#L7

it has to be this way:

static async getInitialProps({ reduxStore, req }) {
    const isServer = !!req;
    await reduxStore.dispatch(serverRenderClock(isServer));

    return {};
  }

All 12 comments

You need to return a promise in serverRenderClock

return new Promise(resolve => {
    setTimeout(() => {
      resolve(dispatch({ type: actionTypes.TICK, light: !isServer, ts: Date.now() }))
    }, 5000)
})

@MarchWorks I also tried Promise but it's not working either. For example, below is my promise

export function fetchListingCount() {
  return (dispatch: any) =>
    axios
      .get("my-listing-count-endpoint.com")
      .then(({ data }) => data)
      .then(data => dispatch(setTotalListingCount(data.ListingCount))); //my action to set the listing count
}

I then used above function in my getInitialProps

static async getInitialProps(props: any) {
    const { store } = props.ctx;
    await store.dispatch(fetchListingCount());
    console.log(store.getState());
  }

I can see from the console.log that redux store on the server side has the listingCount populated
However, when rendered on client side, the listingCount is still 0 (initial value)

@JoeDevGeeeee hey! redux-thunk works fine in my project but I'm using https://github.com/kirill-konshin/next-redux-wrapper
I've checked this example and if you replace with-redux-store lib in here with next-redux-wrapper then it works

@JoeDevGeeeee your example doesn't return a promise do what I commented above

@MarchWorks I used your comment to reproduce the issue so can confirm thatwith-redux-thunk doesn't work for me

@meuwka check it here https://codesandbox.io/s/helloworld-37ycq click on Open in new window (not necessary just to see the delay more clearly.) it will take 10 seconds before the page render

@MarchWorks interesting. even using the same dependencies versions can't make it locally. keep getting 00:00:00 from the server

@meuwka I can't see a significant difference between next-redux-wrapper and with-redux-store but in next-redux-wrapper _app there is

static async getInitialProps ({ Component, ctx }) {
      return {
        pageProps: Component.getInitialProps
          ? await Component.getInitialProps(ctx)
          : {}
      }
    }

which doesn't exist in with-redux-thunk so can you try adding it.

But maybe it has something to do with node version (which doesn't make sense because it does work for next-redux-wrapper)

@MarchWorks yes, you're right. I've found that getInitialProps in index.js is not async https://github.com/zeit/next.js/blob/0dbd3b98eca0bee01a05b8414a60c48abba76abd/examples/with-redux-thunk/pages/index.js#L7

it has to be this way:

static async getInitialProps({ reduxStore, req }) {
    const isServer = !!req;
    await reduxStore.dispatch(serverRenderClock(isServer));

    return {};
  }

@timneutkens Should be closed

How did you guys fixed it? I am having an issue where store.dispatch is not getting called in getInitialProps also, something like:

  static async getInitialProps(props) {
    const {
      store,
    } = props.ctx;
    await store.dispatch(fetchData());
    return {};
  }

But I don't see the data in the redux store when loaded?

@itsmichaeldiego try this

const {
   store,
} = props;

and check if it's called store in your props

Was this page helpful?
0 / 5 - 0 ratings

Related issues

knipferrc picture knipferrc  路  3Comments

ghost picture ghost  路  3Comments

kenji4569 picture kenji4569  路  3Comments

olifante picture olifante  路  3Comments

flybayer picture flybayer  路  3Comments