Store is empty on the frontend
See original GitHub issueThe store with all the reducers are empty on the frontend even though the app populates the reducers on the backend and manages to pull the data that was inserted into the reducer and then use that data to SSR the page.
Here’s my full code, as far as I can see everything is done like in the readme file
_app.js
import App from 'next/app'
import { createWrapper, } from 'next-redux-wrapper'
import { makeStore } from '../store/reducers/rootReducer'
class BaseApp extends App {
static async getInitialProps(context) {
const appProps = await App.getInitialProps(context)
return { ...appProps, }
}
render() {
const { Component, pageProps, } = this.props
return (<Component {...pageProps} />)
}
}
const wrapper = createWrapper(makeStore)
export default wrapper.withRedux(BaseApp)
rootReducer.js
import { createStore, combineReducers, applyMiddleware } from 'redux'
import Thunk from 'redux-thunk'
import exampleReducer from './exampleReducer'
const rootReducer = combineReducers({ exampleReducer })
export const makeStore = () => createStore(
rootReducer, {}/*initial state*/, applyMiddleware(Thunk)
)
exampleReducer.js
import { SET_REPOS } from '../types/exampleTypes'
import { HYDRATE } from 'next-redux-wrapper'
const exampleReducer = (state = {repos:[]}, action) => {
switch(action.type) {
case HYDRATE:
return {...state, ...action.payload};
case SET_REPOS:
return { ...state, repos: action.repos }
default:
return state;
}
}
export default exampleReducer
exampleActions.js
import { SET_REPOS } from '../types/exampleTypes'
import fetch from 'node-fetch'
export const fetchRepos = () => (
async (dispatch, getState) => {
if(getState().exampleReducer.repos.length > 0)
return console.log("repos already loaded")
console.log("loading repos");
//getting newest 5 repos and setting them in the reducer
let repos = await (
await fetch("https://api.github.com/users/kirill-konshin/repos?per_page=5&sort=created:asc")
).json();
//passing to the reducer only the needed data
repos = repos.map(item => ({
name: item.full_name,
url: item.html_url,
desc: item.description,
}))
dispatch({ type: SET_REPOS, repos })
}
)
index.js (page component) - here there are 2 divs, the first one is populated from the data the getInitialProps returns (and on the client side remains populated after the component is mounted), and the second one gets the data directly from the reducer (which in the view-source I can see that the server populated it, but in when the page is mounted this becomes an empty array because for some reason the reducer lose its data in the transition from the backend to the frontend which is the reason for this issue)
import { useSelector } from 'react-redux'
import { fetchRepos } from '../store/actions/exampleActions'
function Home(props) {
const { isServer } = props;
return (<>
<div>{JSON.stringify(props.repos)}</div>
<div>{JSON.stringify(useSelector(state => state.exampleReducer.repos))}</div>
</>)
}
Home.getInitialProps = async (ctx) => {
const { req, store } = ctx;
await store.dispatch(fetchRepos());
const repos = store.getState().exampleReducer.repos;
return { isServer: !!req, repos }
}
export default Home
Issue Analytics
- State:
- Created 3 years ago
- Comments:6 (3 by maintainers)
Top GitHub Comments
All the problems I described are now fixed (you can see the final example project in the link above fully working) I honestly don’t know what caused all these problems and how they suddenly were fixed, what I do know is that one of the problems was solved by changing
action.payload
toaction.playload.exampleReducer
in the hydrate action (which is what caused the reducer to nest itself when the hydrate action was fired and that’s why the repos array always stayed empty…)@kirill-konshin OK the codesandbox is no longer showing the error: https://codesandbox.io/s/modest-shaw-91i3c Edit: now that I’m taking another look at the view-source I can see that even the backend can’t get the data from the reducer using useSelector, so I tried to log the length of the array I should receive from the useSelector and indeed it has a length of 0, meaning something along the way is removing the data from the reducer already on the backend…