Have the following in a component:
<PromoBanner
to="/promo"
style={{
display:
window.location.href.indexOf('promo')!== -1 ? 'none'
:
window.location.href.indexOf('careers')!== -1 ? 'none'
:
window.location.href.indexOf('success')!== -1 ? 'none'
:
'grid'
}}
>
<PromoCruiseImage src={PromoCruise}/>
<PromoHeader>Win a free vacation!</PromoHeader>
<PromoVegasImage src={PromoVegas}/>
</PromoBanner>
which works fine in develop mode.
But when I try to build and/or deploy it, it get this:
failed Building static HTML for pages - 4.244s
ERROR #95312
"window" is not available during server side rendering.
See our docs page for more info on this error: https://gatsby.dev/debug-html
343 | style={{
344 | display:
> 345 | window.location.href.indexOf('promo')!== -1 ? 'none'
| ^
346 | :
347 | window.location.href.indexOf('careers')!== -1 ? 'none'
348 | :
WebpackError: ReferenceError: window is not defined
- Layout.js:345 Layout
src/components/Layout.js:345:15
ERROR
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
in StoreStateProvider
in App
and I have no idea how to fix it...馃ズ
deadline is tomorrow as well 馃く
@rchrdnsh when gatsby generates the pages during the build process, it uses node and with that certain apis are not accessible. With that in mind you have to apply some logic here, you need to use something like mentioned here, You need to check the window defined with something like:
const isBrowser = typeof window !== `undefined`
and adjust the style prop accordingly.
hmmmm...i read through that issue and don't understand at all in any what to do...
tried this:
<PromoBanner
to="/promo"
style={{
if (typeof window !== `undefined`) {
display:
window.location.href.indexOf('promo')!== -1 ? 'none'
:
window.location.href.indexOf('careers')!== -1 ? 'none'
:
window.location.href.indexOf('success')!== -1 ? 'none'
:
'grid'
}
}}
>
but getting 10+ errors and code does not run...
So where would I put that line you wrote to define the browsers window and how would I change the style prop accordingly?
...so lost at the moment 馃様
the code below is not tested and is based on your description.
const fetchLocation = value => {
return window.location.href.indexOf(value) !== -1;
};
const ParentComponent = () => {
const isBrowser = typeof window !== `undefined`;
return (
<div>
{isBrowser && (
<PromoBanner
to="/promo"
style={{
display:
fetchLocation("promo") !== -1
? "none"
: fetchLocation("careers") !== -1
? "none"
: fetchLocation("success") !== -1
? "none"
: "grid"
}}
>
<PromoCruiseImage src={PromoCruise} />
<PromoHeader>Win a free vacation!</PromoHeader>
<PromoVegasImage src={PromoVegas} />
</PromoBanner>
)}
</div>
);
};
What is happening here is the following:
window.location.href.indexOf to a function to make it more cleaner and pragmatic.isBrowser to check to check if the window api is defined and can be accessed.hmmmm....thank you for the option...I implemented it and nothing has broken but the component is not showing up at all...
...also, after looking at that article you linked do you think it would be better to try and render the whole thing or not? Maybe do an if statement and then render or not render the component tree based on routes? That's all I'm really doing with toggling the display property to none. I want the component to render or not based on the route, just trying to wrap my head around this concept and syntax, etc...
Based on what you said, the way i see it, is that you should only render what you need.
// if the component is in a Page component
export default function SomePage ({ location }) {
return (
<PromoBanner
to="/promo"
style={{
display:
location.href.indexOf('promo')!== -1 ? 'none'
:
location.href.indexOf('careers')!== -1 ? 'none'
:
location.href.indexOf('success')!== -1 ? 'none'
:
'grid'
}}
>
<PromoCruiseImage src={PromoCruise}/>
<PromoHeader>Win a free vacation!</PromoHeader>
<PromoVegasImage src={PromoVegas}/>
</PromoBanner>
)
}
// if not
// gatsby use @reach/router under the hood, no need npm install
import { Location } from '@reach/router'
export function BannerWithLocation () {
return (
<Location>
{({ location }) => (
<PromoBanner
style={{
display:
location.href.indexOf('promo') !== -1
? 'none'
: location.href.indexOf('careers') !== -1
? 'none'
: location.href.indexOf('success') !== -1
? 'none'
: 'grid'
}}
to='/promo'
>
<PromoCruiseImage src={PromoCruise} />
<PromoHeader>Win a free vacation!</PromoHeader>
<PromoVegasImage src={PromoVegas} />
</PromoBanner>
)}
</Location>
)
}
hmmmm...here it is in context...I'm using gatsby-plugin-layout to persist this layout component across all pages, but I want this particular component to only show up on certain pages, but persist between pages that it is required by...I tried adding it to certain pages, but then it would get caught up in the page transition animation, which was not desired...
anyway, here is the total component itself, minus the styled component section:
const Layout = ({ children }) => {
useEffect(() => {
if (window.location.href.indexOf('careers')!== -1) {
if (window.location.href.indexOf('#office-manager') !== -1) {
let officeManager = document.querySelector('#office-manager').offsetTop
document.getElementById('main').scrollTop = officeManager
} else if (window.location.href.indexOf('#administrative-assistant') !== -1) {
let administrativeAsistant = document.querySelector('#administrative-assistant').offsetTop
document.getElementById('main').scrollTop = administrativeAsistant
} else if (window.location.href.indexOf('#vacation-counselor') !== -1) {
let vacationCounselor = document.querySelector('#vacation-counselor').offsetTop
document.getElementById('main').scrollTop = vacationCounselor
} else if (window.location.href.indexOf('#marketing-promoter') !== -1) {
let marketingPromoter = document.querySelector('#marketing-promoter').offsetTop
document.getElementById('main').scrollTop = marketingPromoter
} else {
document.getElementById('main').scrollTop = 0
}
} else {
document.getElementById('main').scrollTop = 0
}
})
return (
<App
animate={{ opacity: 1 }}
transition={{
ease: 'easeInOut',
duration: 1,
delay: 0
}}
>
<Menu>
<Logo/>
<Nav/>
<PromoButton/>
</Menu>
<Main id='main'>
{children}
</Main>
<AlmaLogo src={almaLogo} alt="The Alma Logo" />
<PromoBanner
to="/promo"
style={{
display:
window.location.href.indexOf('promo')!== -1 ? 'none'
:
window.location.href.indexOf('careers')!== -1 ? 'none'
:
window.location.href.indexOf('success')!== -1 ? 'none'
:
'grid'
}}
>
<PromoCruiseImage src={PromoCruise}/>
<PromoHeader>Win a free vacation!</PromoHeader>
<PromoVegasImage src={PromoVegas}/>
</PromoBanner>
</App>
)
}
export default injectIntl(Layout)
Layout component from gatsby-plugin-layout also has props.location, similar to Page component.
const Layout = ({ children, location: { href } }) => {
useEffect(() => {
if (href.includes('careers')) {
if (href.includes('#office-manager')) {
const officeManager = document.querySelector('#office-manager')
.offsetTop
document.getElementById('main').scrollTop = officeManager
} else if (href.includes('#administrative-assistant')) {
const administrativeAsistant = document.querySelector(
'#administrative-assistant'
).offsetTop
document.getElementById('main').scrollTop = administrativeAsistant
} else if (href.includes('#vacation-counselor')) {
const vacationCounselor = document.querySelector('#vacation-counselor')
.offsetTop
document.getElementById('main').scrollTop = vacationCounselor
} else if (href.includes('#marketing-promoter')) {
const marketingPromoter = document.querySelector('#marketing-promoter')
.offsetTop
document.getElementById('main').scrollTop = marketingPromoter
} else {
document.getElementById('main').scrollTop = 0
}
} else {
document.getElementById('main').scrollTop = 0
}
}, [href])
return (
<App
animate={{ opacity: 1 }}
transition={{
ease: 'easeInOut',
duration: 1,
delay: 0
}}
>
<Menu>
<Logo />
<Nav />
<PromoButton />
</Menu>
<Main id='main'>{children}</Main>
<AlmaLogo alt='The Alma Logo' src={almaLogo} />
<PromoBanner
style={{
display: href.includes('promo')
? 'none'
: href.includes('careers')
? 'none'
: href.includes('success')
? 'none'
: 'grid'
}}
to='/promo'
>
<PromoCruiseImage src={PromoCruise} />
<PromoHeader>Win a free vacation!</PromoHeader>
<PromoVegasImage src={PromoVegas} />
</PromoBanner>
</App>
)
}
export default injectIntl(Layout)
Also, a tip. Use str.includes instead of str.indexOf.
dang, worked perfectly in gatsby develop mode, but this happened when i ran gatsby build
failed Building static HTML for pages - 4.103s
ERROR #95313
Building static HTML failed for path "/vi/tina/"
See our docs page for more info on this error: https://gatsby.dev/debug-html
303 | <PromoBanner
304 | style={{
> 305 | display: href.includes('promo')
| ^
306 | ? 'none'
307 | : href.includes('careers')
308 | ? 'none'
WebpackError: TypeError: Cannot read property 'includes' of undefined
- Layout.js:305 Layout
src/components/Layout.js:305:25
ERROR
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
in StoreStateProvider
in App
I just checked and href is not available during SSR. You can use location.pathname and location.hash instead. So for e.g. location.pathname.includes('careers'), location.hash === '#office-manager'.
hmmm... swapped them out, like so:
<PromoBanner
style={{
display:
location.pathname.includes('promo')
? 'none'
: location.pathname.includes('careers')
? 'none'
: location.pathname.includes('success')
? 'none'
: 'grid'
}}
to='/promo'
>
...but I still get this error on gatsby build
failed Building static HTML for pages - 4.356s
ERROR #95312
"location" is not available during server side rendering.
See our docs page for more info on this error: https://gatsby.dev/debug-html
301 | style={{
302 | display:
> 303 | location.pathname.includes('promo')
| ^
304 | ? 'none'
305 | : location.pathname.includes('careers')
306 | ? 'none'
WebpackError: ReferenceError: location is not defined
- Layout.js:303 Layout
src/components/Layout.js:303:13
ERROR
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
in StoreStateProvider
in App
...I'm still pretty lost here 馃槙
do I need to import or define anything?
location is from Layout's props
// here you destructure location props to get pathname and hash
// so you don't have to write location.pathname/location.hash everywhere
const Layout = ({ children, location: { pathname, hash } }) => {
useEffect(() => {
if (pathname.includes('careers')) {
if (hash === '#office-manager') {
const officeManager = document.querySelector('#office-manager')
.offsetTop
document.getElementById('main').scrollTop = officeManager
} else if (hash === '#administrative-assistant') {
const administrativeAsistant = document.querySelector(
'#administrative-assistant'
).offsetTop
document.getElementById('main').scrollTop = administrativeAsistant
} else if (hash === '#vacation-counselor') {
const vacationCounselor = document.querySelector('#vacation-counselor')
.offsetTop
document.getElementById('main').scrollTop = vacationCounselor
} else if (hash === '#marketing-promoter') {
const marketingPromoter = document.querySelector('#marketing-promoter')
.offsetTop
document.getElementById('main').scrollTop = marketingPromoter
} else {
document.getElementById('main').scrollTop = 0
}
} else {
document.getElementById('main').scrollTop = 0
}
}, [hash, pathname]) // also here you need both pathname and hash
return (
<App
animate={{ opacity: 1 }}
transition={{
ease: 'easeInOut',
duration: 1,
delay: 0
}}
>
<Menu>
<Logo />
<Nav />
<PromoButton />
</Menu>
<Main id='main'>{children}</Main>
<AlmaLogo alt='The Alma Logo' src={almaLogo} />
<PromoBanner
style={{
display: pathname.includes('promo')
? 'none'
: pathname.includes('careers')
? 'none'
: pathname.includes('success')
? 'none'
: 'grid'
}}
to='/promo'
>
<PromoCruiseImage src={PromoCruise} />
<PromoHeader>Win a free vacation!</PromoHeader>
<PromoVegasImage src={PromoVegas} />
</PromoBanner>
</App>
)
}
export default injectIntl(Layout)
wait a minute, i needed to change the thing in the curly braces at the beginning of the component!, ah-ha! So it compiled now in gatsby build!!!
Yeah you can learn more about object destructuring here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
Also note the useEffect dependency array.
holy doodle smacks! I think it works again! Need to upload it to netlify to make sure it builds, but thank you @jonniebigodes and @universse!!! 馃
I will close this out after is successfully deploys :-)
i see the destructuring, and it looks nice! I will implement that as well!
Anyhoo, it totally build and is working now at
yay!
Nice site :)
thanks XD
...also, it seems that the location prop is not really documented for the layout plugin? Am I missing something?
It's mentioned here https://www.gatsbyjs.org/docs/browser-apis/#wrapPageElement which gatsby-plugin-layout use under the hood. I agree that can be improved upon.
i see, it's in the thing that the other thing is wrapped around...thank you :-)
Most helpful comment
i see the destructuring, and it looks nice! I will implement that as well!
Anyhoo, it totally build and is working now at
www.alma.vacations
yay!