Skip to content

Next.JS Redux dispatch not working in getStaticProps()

I am pretty new to Next.JS and I was trying to set up Redux with my Next.JS application. Now my page is supposed to display a list of posts that I am calling in from an API. The page renders perfectly when I’m dispatching from useEffect() to populate the data on to my page, but getStaticProps() or getServerSideProps() are not working whatsoever!

Here is a bit of code that will give you a hint of what I’ve done so far:

store.js

import { useMemo } from 'react'
import { createStore, applyMiddleware } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import thunk from 'redux-thunk'
import rootReducer from './reducers/rootReducer'

const initialState = {}
const middlewares = [thunk]

let store

function initStore(preloadedState = initialState) {
    return createStore(
        rootReducer,
        preloadedState,
        composeWithDevTools(applyMiddleware(...middlewares))
    )
}

export const initializeStore = (preloadedState) => {
    let _store = store ?? initStore(preloadedState)

    if (preloadedState && store) {
        _store = initStore({
            ...store.getState(),
            ...preloadedState,
        })
        store = undefined
    }

    if (typeof window === 'undefined') return _store
    if (!store) store = _store

    return _store
}

export function useStore(initialState) {
    const store = useMemo(() => initializeStore(initialState), [initialState])
    return store
}

action.js

export const fetchPosts = () => async dispatch => {
    const res = await axios.get('https://jsonplaceholder.typicode.com/posts')

    dispatch({
        type: FETCH_POSTS,
        payload: res.data
    })
}

_app.js

import { Provider } from 'react-redux'
import { createWrapper } from 'next-redux-wrapper'
import { useStore } from '../redux/store'

export default function MyApp({ Component, pageProps }) {
  const store = useStore(pageProps.initialReduxState)

  return (
    <Provider store={store}>
      <Component {...pageProps} />
    </Provider>
  )
}

These are the files that I needed for the basic redux setup. Once my store was set up and I wrapped my app around the Provider, I initially though of using useEffect() hook to populate data on a component that was rendering inside my index.js file.

component.js

import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { fetchPosts } from '../redux/actions/postsAction'

const Posts = () => {
    const dispatch = useDispatch()
    const { items } = useSelector(state => state.posts)

    useEffect(() => {
        dispatch(fetchPosts())
    }, [])

    return (
        <div className="">
            <h1>Posts</h1>

            {items.map(post => {
                return (<div key={post.id}>
                    <h3>{post.title}</h3>
                    <p>{post.body}</p>
                </div>)
            })}
        </div>
    )
}

export default Posts

This worked perfectly! All my posts were showing up inside the component. The problem occurred when I was trying to achieve the same behaviour with server side rendering (or even SSG). I wanted to populate the data during the pre-render phase but for some reason the items array which is supposed to hold all the data is empty, basically meaning that the disptacher was never called! Here is the piece of code that is bothering me (exactly same as previous code, but this time I’m using getStaticProps() instead of useEffect()):

component.js

import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { fetchPosts } from '../redux/actions/postsAction'

const Posts = ({ items }) => {
    return (
        <div className="">
            <h1>Posts</h1>

            {items.map(post => {
                return (<div key={post.id}>
                    <h3>{post.title}</h3>
                    <p>{post.body}</p>
                </div>)
            })}
        </div>
    )
}

export async function getStaticProps() {
    console.log('Props called')
    const dispatch = useDispatch()
    const { items } = useSelector(state => state.posts)

    dispatch(fetchPosts())
    console.log(items)

    return { props: { items } }
}

export default Posts

By running this, I’m getting an error that items is empty! Please help me, I have no clue what’s going wrong here.

Answer

Well I fixed this issue myself but I forgot to post an answer for it, my bad!

The problem here really is very simple, hooks don’t work outside of a functional component!