gatsby: Styled component doesn't have access to its (theme) props on 404.html page

Description

Components being used on 404 page don’t have access to passed props. I have this issue with styled components (accessing theme prop inside them), so example will be based on that.

Steps to reproduce

gatsby new gatsby-site yarn add styled-components

layouts/index.js file:

...
import { ThemeProvider } from 'styled-components'
...
const Layout = ({ children, data }) => (
  <ThemeProvider theme={{ foo: { bar: 'baz' } }}>
    ...
  </ThemeProvider>
)
...

404.js file:

import React from 'react'
import styled from 'styled-components'

const Debugger = styled.div`
  ${({ theme }) => console.log(theme.foo.bar)};
`

const NotFoundPage = props => (
  <div>
    <h1>NOT FOUND</h1>
    <p>You just hit a route that doesn&#39;t exist... the sadness.</p>
    <Debugger />
  </div>
)

export default NotFoundPage

Expected result

Component on 404 page should have access to its props.

Actual result

Running gatsby build && gatsby serve and accessing nonexistent route yields such results: screenshot from 2018-05-21 19-01-21

Environment

  • Gatsby version (npm list gatsby): gatsby@1.9.250
  • gatsby-cli version (gatsby --version): 1.1.52
  • Node.js version: v8.11.1
  • Operating System: antergos linux

File contents (if changed)

gatsby-config.js: N/A package.json: added styled-components ^3.2.6 gatsby-node.js: N/A gatsby-browser.js: N/A gatsby-ssr.js: N/A

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 31 (23 by maintainers)

Most upvoted comments

@markph1990 Thanks. I’m pretty sure this is a Gatsby issue. I can actually navigate to /404 even in production and the page renders without issues, however a genuine missing page causes the error.

This error occurs locally using yarn serve.

If a live site would help with debugging, here the demo for a starter I’ve been working on deployed to Surge and the exact same issue is present:

  • here is a link to a page that doesn’t exist.

If I rip out the components on the 404 page and just render the props that are passed into the page I can see the page is rendered twice.

On the initial render the props are:

{
  "match": { "path": "/", "url": "/", "params": {}, "isExact": false },
  "location": { "pathname": "/404.html", "search": "", "hash": "" },
  "history": {
    "action": "POP",
    "location": { "pathname": "/404.html", "search": "", "hash": "" }
  },
  "staticContext": {},
  "data": {
    "site": {
      "siteMetadata": {
        "structure": { "pages": { "notFound": { "title": "Page Not Found" } } }
      }
    }
  },
  "pathContext": {}
}

On the second render the props are (and theme is undefined in any styled components):

{
  "page": true,
  "location": { "pathname": "/404.html" },
  "data": {
    "site": {
      "siteMetadata": {
        "structure": { "pages": { "notFound": { "title": "Page Not Found" } } }
      }
    }
  },
  "pathContext": {}
}

You can see this happen here

You can see this locally by:

  1. Clone https://github.com/Undistraction/gatsby-skeleton-starter
  2. yarn
  3. yarn build
  4. yarn serve
  5. open http://localhost:9000/

Workaround

Wrap the contents of the 404 page in its own ThemeProvide, for exampler:

const FourOhFourPage = ({ data, location }) => (
  <ThemeProvider theme={theme}>
    <Page>
      <NotFoundMessage/>
    </Page>
  </ThemeProvider>
)