Gatsby: [1.0] Question - How to gatsby+redux ssr successfully?

Created on 1 Jun 2017  Â·  15Comments  Â·  Source: gatsbyjs/gatsby

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.

question or discussion

Most helpful comment

@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

All 15 comments

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

@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?

@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.

@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.

@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.

An example site would be fantastic!

On Thu, Jun 1, 2017 at 8:32 AM Scotty Eckenthal notifications@github.com
wrote:

@KyleAMathews https://github.com/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.

—
You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub
https://github.com/gatsbyjs/gatsby/issues/1079#issuecomment-305530788,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEVh-9PQyo4L-Y5vlZH75AwGe6aig8tks5r_tmOgaJpZM4NtBvv
.

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.

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

@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

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!

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

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.

Cl

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!

@caki0915
image

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mikestopcontinues picture mikestopcontinues  Â·  3Comments

Oppenheimer1 picture Oppenheimer1  Â·  3Comments

brandonmp picture brandonmp  Â·  3Comments

theduke picture theduke  Â·  3Comments

3CordGuy picture 3CordGuy  Â·  3Comments