Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Populating store with getInitialProps #36

Closed
JeSuis opened this issue Jul 14, 2017 · 8 comments
Closed

Populating store with getInitialProps #36

JeSuis opened this issue Jul 14, 2017 · 8 comments

Comments

@JeSuis
Copy link

JeSuis commented Jul 14, 2017

While I'm able to get data and pass them as props to the component I'm unable to populate the store.
I'm successfully hitting my action and reducer, I see the data in the terminal when the page loads but the store just stays with the default value.

In my component

  static async getInitialProps ({ store, isServer}) {
    const res = await store.dispatch(getMovies(isServer));
    return res.data;
  }

Action

export const getMovies = (isServer) => dispatch => (
      axios.get('https://api.themoviedb.org/xxxxxx')
          .then(response => dispatch({ type: constants.GET_MOVIES, data: response.data }))
);

Reducer

const movies = (state = initialState, action) => {
  switch (action.type) {
    case constants.GET_MOVIES:
      return {...state, foo: action.data};
    default:
      return {foo: 'cucumber'}
  }
};

I was thinking it had something to do with here, but trying to pass in state has had no luck

export default withRedux(initStore, (state) => ({foo: state.foo}), mapDispatchToProps)(Movies)
@kirill-konshin
Copy link
Owner

kirill-konshin commented Jul 14, 2017

Do you see expected data in props directly?

const res = await store.dispatch(getMovies(isServer));
// do console.log(res) here
return res.data;

It seems that your action is breaking the promise chain somewhere, e.g. getInitialProps returns value and the page is rendered before the action is dispatched. You can also add console.log before you dispatch constants.GET_MOVIES.

Hope this helps. If not — create a repo where I will be able to reproduce the behavior, I will take a look.

P.S. Also chain may become broken because of Redux Thunk, so try this:

static async getInitialProps ({ store, isServer}) {
  const res = await getMovies(isServer)(store.dispatch);
  return res.data;
}

@JeSuis
Copy link
Author

JeSuis commented Jul 14, 2017

Yes I do, above where you commented and I also tried before dispatching the reducer, the props are also available in the normal react life cycles which confuses me cause it seems like everything else works. I almost feel like its getting overridden somehow.
The change for redux didn't work either.

Put a repo up here, thanks for taking a look
https://github.com/JeSuis/next-redux-test

@michaeljonathanblack
Copy link

michaeljonathanblack commented Jul 14, 2017

What's the purpose of passing isServer around?

Also, when getInitialProps is called on the server and the component rendered using the store, how is the store rehydrated on the client with the same data? Does this library handle that?

e.g. http://redux.js.org/docs/recipes/ServerRendering.html

window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\u003c')}

What if I'm using a custom _document.js?

These are all general questions that might help to answer the issue, but are in truth mostly for me. My guess is that the state isn't being rehydrated on the client because of something above, but I don't have enough understanding.

Edit: Interesting, I see the initialState inside __NEXT_DATA__ on the client. I'm not quite sure how this all works together! Anywho, I'm probably wrong 👍

@JeSuis
Copy link
Author

JeSuis commented Jul 15, 2017

I ended up not needing isServer, I've since removed it locally.

I was under the impression this is where it would get hydrated, but I could be wrong.
And the wrapper should be taking care of most things according to the docs.

export default withRedux(initStore, (state) => ({foo: state.foo}), mapDispatchToProps)(Movies)

I am using _document.js but I'm not making any data calls there, its just for css setup, I know there's race conditions using it with data calls.

I have since noticed something. I caused an error and the script halted and the store was populated.

So this leads me to think its getting overridden and the action type is undefined so the default condition gets chose, but for the life of me I can't see what would be causing it to get trigged more than once.

@michaeljonathanblack
Copy link

I can't get a redux-thunk example working myself.

Here is my code (TITLES_REQUEST is never logged):

import React from 'react';
import fetch from 'isomorphic-unfetch';
import dynamic from 'next/dynamic';
import withRedux from 'next-redux-wrapper';
import makeStore from 'state/makeStore';
import Layout from 'components/Layout';

const Home = dynamic(import('../components/Home'));

const getTitles = () => dispatch => {
  console.log('TITLES_REQUEST');
  try {
    return fetch('https://api.tvmaze.com/search/shows?q=batman')
      .then(res => res.json())
      .then(data => {
        const shows = data.map(item => item.show);
        dispatch({ type: 'TITLES_SUCCESS', titles: shows });
      });
  } catch (e) {
    return dispatch({ type: 'TITLES_ERROR', titles: [] });
  }
};

class HomePage extends React.Component {
  static async getInitialProps({ store }) {
    store.dispatch({ type: 'PLUS' });
    return store.dispatch(getTitles);
  }

  render() {
    return (
      <Layout>
        <Home {...this.props} />
      </Layout>
    );
  }
}

export default withRedux(makeStore)(HomePage);

@JeSuis
Copy link
Author

JeSuis commented Jul 15, 2017

So it looks like according to this I'm trying to hydrate the store client side correctly, I even tried it in createStore directly but have the same results where it has the default initial state as if something is overwriting it.
reduxjs/redux#1189

Note you can also get the server populated state from __NEXT_DATA.props.initialState

So I'm not sure if its this library or what causing the problem, the code I put together is pretty minimal.

@mherodev if you have a repo I can install from for your issue I can see if I have time this weekend to take a look.

@JeSuis
Copy link
Author

JeSuis commented Jul 15, 2017

Found my problem, initialState was always getting set to just that.
Instead should have been using state with initialState as a fallback, didn't even have to change any other areas, the library seems to be taking care of it all.

Thanks for the help and the library.

@JeSuis JeSuis closed this as completed Jul 15, 2017
@michaeljonathanblack
Copy link

Whoops, I wasn't calling my action creator, that's why! We're good ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants