1
votes

I'm trying to fetch data from API by triggering a 'getItems' action in getInitialProps in a page.(Let's say it is page A)

Data can be successfully fetched if I go to page A from other page through Link(next/link).

However if I refresh in page A, data never get fetched and I have to manually fetch data by triggering the getItems action.

Could anyone let me know what I should do to fetch data even when refreshing the page?

_app.js

const MyApp = props => {
  const { Component, pageProps, store } = props

  return (
    <>
      <Head>
        <link rel='stylesheet' href='/styles/global.css' />
      </Head>
      <Provider store={store}>
        <MainLayout>
          <Component {...pageProps} />
        </MainLayout>
      </Provider>
    </>
  )
}

MyApp.getInitialProps = async ({ Component, ctx }) => {
  const pageProps = Component.getInitialProps
    ? await Component.getInitialProps(ctx)
    : {}
  return { pageProps }
}

export default withRedux(store)(MyApp)

pageA.js

import Head from 'next/head'
import Link from 'next/link'
import { connect } from 'react-redux'
import { getItems, addItem } from '../../store/actions/itemAction'
import { GET_ITEMS } from '../../store/types'

const Index = props => {
  return (
    <>
      <Head>
        <title>Item List</title>
        <link rel='stylesheet' href='/styles/css_pages/shop.css' />
      </Head>
      <div><div>
    </>
  )
}

Index.getInitialProps = async ({ store }) => {
  await store.dispatch(getItems())
  return {}
}

const mapStateToProps = state => ({
  goods: state.item.goods,
})

const mapDispatchToProps = dispatch => ({
  getItems: () => dispatch(getItems()),
  addItem: () => dispatch(addItem()),
})

export default connect(mapStateToProps, mapDispatchToProps)(Index)

itemAction.js

import fetch from 'isomorphic-unfetch'
import { GET_ITEMS } from '../types'

export const getItems = () => {
  return dispatch => {
    fetch('http://localhost:5000/item')
      .then(res => res.json())
      .then(data => dispatch({ type: GET_ITEMS, payload: data }))
      .catch(err => console.error(err))
  }
}

itemReducer.js

import { GET_ITEMS } from '../types'

const initialState = { goods: [], loading: false }

const itemReducer = (state = initialState, action) => {
  switch (action.type) {
    case GET_ITEMS:
      return {
        ...state,
        goods: action.payload,
        loading: false,
      }

    default:
      return state
  }
}

export default itemReducer

store.js

import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import rootReducer from './rootReducer'

const bindMiddleware = middleware => {
  if (process.env.NODE_ENV !== 'production') {
    const { composeWithDevTools } = require('redux-devtools-extension')
    return composeWithDevTools(applyMiddleware(...middleware))
  }

  return applyMiddleware(...middleware)
}

export const store = () => createStore(rootReducer, bindMiddleware([thunk]))

rootReducer.js

import { combineReducers } from 'redux'
import itemReducer from './reducers/itemReducer'

const rootReducer = combineReducers({
  item: itemReducer
})

export default rootReducer

2

2 Answers

0
votes

You should wait for the getItems action response in your pageA's getInitialProps before returning and rendering.

I think if you try to use an await, it'll solve your problem:

Index.getInitialProps = async ({ store }) => {
  await store.dispatch(getItems())
  return {}
}
0
votes

I would try to look into this example https://github.com/vercel/next.js/blob/canary/examples/with-redux-wrapper/store/store.js

It is recommended to use the next-redux-wrapper package to wrap your pages. Then you will have the store object available on your Index.getInitialProps