Gatsby server-side rendering of page with client-only routes, based on window location

冷暖自知 提交于 2020-01-25 06:49:28

问题


I am working on a Gatsby project (a language learning blog) and am having trouble with an issue that only happens in production builds due to server-side rendering.

I programmatically generate a page for each blog post with the following scheme: /posts/{post-name}. Each post can also have a number of subpaths that map to open tabs in the UI. For example, /posts/important-spanish-verbs/lesson would open the lesson tab. Each page has a matchPath property of /posts/{post-name}/*, and these are handled as client-only routes, implemented with reach-router.

With gatsby develop, the app works exactly as intended. When I visit /posts/some-post/podcast, it successfully opens to the podcast tab and I can see the active tab being set correctly.

The problem is that with gatsby build && gatsby serve, when I fresh-load a URL that directly navigates to a specific tab inside of the post (either manually visiting the whole URL or refreshing), the active tab is not set correctly in the UI.

The following snippet (highly simplified and condensed to demonstrate the issue) roughly outlines the problem:

function TabbedLayout({ children, basePath }) {
  return (
    <LocationProvider>
      {({ location }) => {
        return (
          <Fragment>
            <ul>
              React.Children.map(children, (child, index) => {
                const isActive = child.props.path === location.pathname
                console.log(`tab ${child.props.path} active? ${isActive}`)
                return <li className={isActive ? 'active' : 'inactive'}>{/* construct a link based on child props */}</li>
              })
            </ul>
            <Router basepath={basePath}>
              {children}
            </Router>
          </Fragment>
        )
      }}
    </LocationProvider>
}

What happens when I run my code which uses the method demonstrated above in a production build (with SSR) is that when I visit for example posts/example-post/lesson:

  • The content is rendered correctly via Reach router (i.e. the content of the lesson tab is open)
  • The lesson tab has class inactive (an error)
  • In the console, I see tab /posts/example-post/lesson active? true printed, even though the CSS class didn't get updated!

I've tried everything I can think of to try to update the UI. As soon as I click a different tab and the window location changes without a refresh, everything updates fine and the active tab UI works as expected, but I just cannot seem to get it to re-render based on the isActive variable.

Does anyone know a way to fix or work around this issue?

Thanks!


回答1:


I have managed to find a workaround for the issue, although it's a bit frustrating to not understand in detail why the problem is actually happening.

If I wrap the tab <li>s (which don't correctly show as active/inactive on first load with SSR) in a condition to check that we're in the browser, it works:

return typeof window !== 'undefined' && (
  <li className={isActive ? 'active' : 'inactive'}>
    {/* construct a link based on child props */}
  </li>
)


来源:https://stackoverflow.com/questions/59805587/gatsby-server-side-rendering-of-page-with-client-only-routes-based-on-window-lo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!