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

[1.0] Question - How to gatsby+redux ssr successfully? #1079

Closed
scottyeck opened this issue Jun 1, 2017 · 15 comments
Closed

[1.0] Question - How to gatsby+redux ssr successfully? #1079

scottyeck opened this issue Jun 1, 2017 · 15 comments
Labels
type: question or discussion Issue discussing or asking a question about Gatsby

Comments

@scottyeck
Copy link
Contributor

If you use replaceRouterComponent to wrap your <Router> in with a <Provider> - necessary with use of react-router-redux, since your <Router> should be passed a store instance - then because the <Router> gets replaced with a <StaticRouter> in the static-entry, this <Provider> isn't available at ssr-time. As a result, if the ssr-process attempts to render a connected-component, an error of the following type is thrown:

Generating HTML failed

Error: Invariant Violation: Could not find "store" in either the context or props of "Connect(Counter)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(Counter)".
    at invariant (render-page.js:21035:16)
    at new Connect (render-page.js:42710:34)
    at ReactCompositeComponent._constructComponentWithoutOwner (render-page.js:14787:17)
    at ReactCompositeComponent._constructComponent (render-page.js:14774:20)
    at ReactCompositeComponent.mountComponent (render-page.js:14677:22)
    at Object.ReactReconciler.mountComponent (render-page.js:7783:36)
    at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (render-page.js:13880:45)
    at ReactDOMComponent.Mixin._createContentMarkup (render-page.js:10897:33)
    at ReactDOMComponent.Mixin.mountComponent (render-page.js:10764:30)
    at Object.ReactReconciler.mountComponent (render-page.js:7783:36),Invariant Violation: Could not find "store" in either the context or props of "Connect(Counter)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(Counter)".
    at invariant (render-page.js:21035:16)
    at new Connect (render-page.js:42710:34)
    at ReactCompositeComponent._constructComponentWithoutOwner (render-page.js:14787:17)
    at ReactCompositeComponent._constructComponent (render-page.js:14774:20)
    at ReactCompositeComponent.mountComponent (render-page.js:14677:22)
    at Object.ReactReconciler.mountComponent (render-page.js:7783:36)
    at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (render-page.js:13880:45)
    at ReactDOMComponent.Mixin._createContentMarkup (render-page.js:10897:33)
    at ReactDOMComponent.Mixin.mountComponent (render-page.js:10764:30)
    at Object.ReactReconciler.mountComponent (render-page.js:7783:36),Invariant Violation: Could not find "store" in either the context or props of "Connect(Counter)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(Counter)".
    at invariant (render-page.js:21035:16)
    at new Connect (render-page.js:42710:34)
    at ReactCompositeComponent._constructComponentWithoutOwner (render-page.js:14787:17)
    at ReactCompositeComponent._constructComponent (render-page.js:14774:20)
    at ReactCompositeComponent.mountComponent (render-page.js:14677:22)
    at Object.ReactReconciler.mountComponent (render-page.js:7783:36)
    at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (render-page.js:13880:45)
    at ReactDOMComponent.Mixin._createContentMarkup (render-page.js:10897:33)
    at ReactDOMComponent.Mixin.mountComponent (render-page.js:10764:30)
    at Object.ReactReconciler.mountComponent (render-page.js:7783:36),Invariant Violation: Could not find "store" in either the context or props of "Connect(Counter)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(Counter)".
    at invariant (render-page.js:21035:16)
    at new Connect (render-page.js:42710:34)
    at ReactCompositeComponent._constructComponentWithoutOwner (render-page.js:14787:17)
    at ReactCompositeComponent._constructComponent (render-page.js:14774:20)
    at ReactCompositeComponent.mountComponent (render-page.js:14677:22)
    at Object.ReactReconciler.mountComponent (render-page.js:7783:36)
    at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (render-page.js:13880:45)
    at ReactDOMComponent.Mixin._createContentMarkup (render-page.js:10897:33)
    at ReactDOMComponent.Mixin.mountComponent (render-page.js:10764:30)
    at Object.ReactReconciler.mountComponent (render-page.js:7783:36)

I've attempted to resolve this (thus far unsuccessfully) using the replaceServerBodyRender hook in gatsby-node.js - see example here: https://github.com/fabrictech/gatsby/tree/redux-example/examples/redux.

I'm hoping that a new apiRunner hook needn't be added to achieve this, but if so, I'm happy to work on it and/or consult. Any suggestions or guidance would be awesome.

@akadop
Copy link
Contributor

akadop commented Jun 1, 2017

Silly question but how would you SSR if this is a static site?

@scottyeck
Copy link
Contributor Author

@akadop Not a silly question at all! I suppose the terminology is confusing, and frankly I'm not even sure I'm using it correctly. I'm referring to the build-html phase that gets executed by gatsby build to generate the static HTML. I'm using the ssr terminology since the hooks in gatsby-node.js get executed by the api-runner-ssr util. Does that make sense? Am I crazy?

@KyleAMathews
Copy link
Contributor

@akadop I was thinking about that the other day — we might not want to use ssr terminology cause yeah, it doesn't make as much sense for a static build process. The reason we do use it is because that's what the rest of the React world uses.

@KyleAMathews
Copy link
Contributor

@scottyeck it looks actually right except you need to put the API implementation in gatsby-ssr.js not gatsby-node.js.

We really need to get API validation in pronto. It's super easy to get tripped up by silly stuff like this and it's very easy to automatically validate. I might do something really simple today actually.

@scottyeck
Copy link
Contributor Author

@KyleAMathews Oops - thanks for looking. I probably should have picked up on that when I looked through the source. Thanks for your help!

Obviously moving the implementation into gatsby-ssr.js got past that error. Working through a few more issues but happy to PR the example if you'd like.

@KyleAMathews
Copy link
Contributor

KyleAMathews commented Jun 1, 2017 via email

@scottyeck
Copy link
Contributor Author

No problem at all - setting them up is really helpful as a POC before I move into development in our app. Also, it lays the foundation for a plugin later on.

@oltodo
Copy link
Contributor

oltodo commented Jul 28, 2017

Hi, I followed the PR's example but I still get the error on build.
It should be work?

@salzbrenner
Copy link

@oltodo bit late but did you figure it out?

If you're using any gatsby-plugins, make sure none of them are overwriting gatsby-ssr.js.

For my project this error occurred after adding gatsby-plugin-styled-components. Was able to replicate same behavior for the example as well, if the plugin is added to gatsby-config.js. I guess this occurs because gatsby-plugin-styled-components provides support for SSR by default, including it's own gatsby-ssr.js. Drove me a bit nuts, as the plugin file was overriding my own gatsby-ssr.js and was not aware of that!

Anyway, to get the example working with styled-components I had to remove from gatsby-config.js and update gatsby-ssr.js to:

import React from 'react'
import { Provider } from 'react-redux'
import { renderToString } from 'react-dom/server'
import { ServerStyleSheet } from 'styled-components'

import createStore from './src/state/createStore'

exports.replaceRenderer = ({ bodyComponent, replaceBodyHTMLString, setHeadComponents }) => {

    const store = createStore()

    const ConnectedBody = () => (
        <Provider store={store}>
            {bodyComponent}
        </Provider>
    )

    // Add styled-components SSR
    const sheet = new ServerStyleSheet()
    const bodyHTML = renderToString(sheet.collectStyles(<ConnectedBody />))
    const styleElement = sheet.getStyleElement()

    replaceBodyHTMLString(bodyHTML)
    setHeadComponents(styleElement)
}

Maybe this is obvious, but being new to Gatsby this caused a couple hours of debugging ... @KyleAMathews maybe a note can be added either to the Redux example or the gatsby-plugin-styled-components readme that mentions this? Happy to PR

@KyleAMathews
Copy link
Contributor

Oh right — this has been a TODO for a while so would love it if you want to tackle it! Basically when we load plugins, we should detect if there's multiple plugins that implement certain APIs (like replaceRenderer and warn that there'll be problems. Sorry for the wasted debugging time! Would love it you could write the warning code for this!

@salzbrenner
Copy link

Will try to get to it in the next couple weeks, no need to be sorry, really liking Gatsby so far!

@oltodo
Copy link
Contributor

oltodo commented Sep 26, 2017

Your solution works fine for me @aboutevan. Thanks for your research! Fortunately for us, the styled-components plugin's code is very simply and is not hard to duplicate.

@KyleAMathews
Copy link
Contributor

Cl

@cjkihl
Copy link
Contributor

cjkihl commented Feb 19, 2018

If anyone looking complete example that's using Redux and Redux-Devtools together with CSS-in-JS;
I put together a startersite: Gatsby-starter-redux
Demo here.
Hope it can be useful!

@fk fk added the type: question or discussion Issue discussing or asking a question about Gatsby label Feb 19, 2018
@Nantris
Copy link

Nantris commented Jun 15, 2018

@caki0915
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: question or discussion Issue discussing or asking a question about Gatsby
Projects
None yet
Development

No branches or pull requests

9 participants