问题
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